细节有点多的水题。
设
w
i
,
j
w_{i,j}
wi,j 表示第
i
i
i 行删掉
j
j
j 个 1
后的最小花费代价,
f
i
,
j
f_{i,j}
fi,j 表示前
i
i
i 行删掉
j
j
j 个 1
后的最小花费代价。
容易发现 w w w 数组能够很容易地求到,接下来考虑 f f f 数组。可以发现这是个背包模型,转移式子为:
f i , j = min 0 ≤ l ≤ j ≤ k { f i − 1 , l + w i , j − l } f_{i,j} = \min\limits_{0\leq l\leq j\leq k}\{f_{i-1,l}+w_{i,j-l}\} fi,j=0≤l≤j≤kmin{fi−1,l+wi,j−l}
//CF946D
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 510;
int n, m, k, pos[N], w[N][N], f[N][N];
char s[N];
int main(){
memset(w, 0x3f, sizeof(w));
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; ++ i){
scanf("%s", s+1);
int tot = 0;
for(int j = 1; j <= m; ++ j){
if(s[j] == '1') pos[++tot] = j;
}
for(int j = 0; j <= tot; ++ j){
int len = tot - j;
for(int l = 1; l + len - 1 <= tot; ++ l){
w[i][j] = min(w[i][j], pos[l+len-1] - pos[l] + 1);
}
w[i][tot] = 0;
}
}
memset(f, 0x3f, sizeof(f));
f[0][0] = 0;
for(int i = 1; i <= n; ++ i){
for(int j = 0; j <= k; ++ j){
for(int l = 0; l <= j; ++ l){
f[i][j] = min(f[i][j], f[i-1][l] + w[i][j-l]);
}
}
}
int ans = 0x3f3f3f3f;
for(int i = 0; i <= k; ++ i){
ans = min(ans, f[n][i]);
}
printf("%d\n", ans);
return 0;
}