#include #include #include #include using ll = int64_t; using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(0); ll n, m, k; cin >> n >> m >> k; vector v(n); for (ll i = 0; i < n; i++) { cin >> v[i]; } vector dp(k + 1, 1e9); dp[0] = 0; for (ll i = 0; i < n; i++) { vector a; for (ll j = 0; j < m; j++) { if (v[i][j] == '1') { a.push_back(j); } } ll p = a.size(); vector f(p + 1, 0); if (p == 0) { vector ndp = dp; dp = move(ndp); continue; } f[p] = 0; for (ll t = 0; t < p; t++) { ll b = p - 1 - t; ll mval = 1e9; for (ll x = 0; x <= t; x++) { ll cost = a[b + x] - a[x] + 1; if (cost < mval) { mval = cost; } } f[t] = mval; } vector ndp(k + 1, 1e9); for (ll j = 0; j <= k; j++) { for (ll t = 0; t <= min(p, j); t++) { if (dp[j - t] != 1e9) { if (dp[j - t] + f[t] < ndp[j]) { ndp[j] = dp[j - t] + f[t]; } } } } dp = move(ndp); } ll ans = *min_element(dp.begin(), dp.end()); cout << ans << endl; return 0; } /* 输入处理: 读取矩阵的行数 n、列数 m 和最多可删除的1的数量 k。 读取矩阵的每一行字符串。 动态规划初始化: 初始化 dp 数组,大小为 k+1,dp[0] = 0 表示初始状态(无删除)的代价为0,其余初始化为一个大数(表示不可达)。 处理每一行: 收集每行中1的位置索引到数组 a。 如果该行没有1,则直接跳过(代价为0)。 否则,计算该行删除 t 个1后的最小代价 f(t): f[p] = 0 表示删除所有1后代价为0。 对于 0 ≤ t < p,计算删除左侧 x 个和右侧 y 个1(x + y = t)后,剩余1的第一个和最后一个位置形成的区间长度,取最小值作为 f(t)。 更新动态规划状态: 对于当前行,枚举总删除数 j(0 到 k),枚举当前行删除数 t(0 到 min(p, j))。 更新 ndp[j] 为 dp[j - t] + f[t] 的最小值。 输出结果: 最终答案为 dp[0..k] 中的最小值,即所有行在删除不超过 k 个1的情况下的最小总代价。 */