写得很折磨人,每次dp都写个一个多小时,写出来明明觉得不难 .
-
题目大意:可以进行K次操作,把删除1,进行k次操作后每行第一个 1 和最后一个 1 的位置 相减的绝对值加 1 得到的结果最小。
-
做法:每次肯定是要从左删或者从右边删,然后顺着这个思路,先把每行的进行小于等于k次操作时, 每行最小的值存下来, 我用f[i][j], i 代表第几行, j 代表几次操作。这个直接暴力,枚举所有情况。左零次,右边 1 ...... k 次这样暴力。把值求出来后,就直接套分组背包的模板就行。
const int N = 510;
char g[N][N];
int f[N][N], dp[N][N], s[N];
void solve()
{
int n, m, k;
cin >> n >> m >> k;
int sum = 0;
memset(f, -0x3f, sizeof f);
for (int i = 1; i <= n; i ++)
{
int a[m + 1] = {0};
int l = 1, r = 0;
for (int j = 1; j <= m; j ++)
{
cin >> g[i][j];
if (g[i][j] == '1') a[++ r] = j;
}
f[i][0] = 0;
if (r == 0) continue;
sum += a[r] - a[l] + 1;
int maxx = min(k, r - l + 1);
for (int j = 1; j <= maxx; j ++)
{
if (j == r - l + 1) {f[i][j] = a[r] - a[l] + 1;continue;}
for (int p = 0; p <= j; p ++)
{
int res = a[r - (j - p)] - a[l + p] + 1;
f[i][j] = max(f[i][j], a[r] - a[l] + 1 - res);
}
}
s[i] = maxx;
}
for (int i = 1; i <= n; i ++)
{
for (int j = 0; j <= k; j ++)
{
dp[i][j] = dp[i - 1][j];
for (int l = 0; l <= s[i]; l ++)
{
if (j >= l) dp[i][j] = max(dp[i][j], dp[i - 1][j - l] + f[i][l]);
}
}
}
cout << sum - dp[n][k] << '\n';
}
标签:39,Rated,--,Educational,Codeforces,int,每行,dp
From: https://www.cnblogs.com/NNNZZZ/p/17347870.html