P4158 [SCOI2009]粉刷匠(线性dp)
windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。
windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。
如果windy只能粉刷 T 次,他最多能正确粉刷多少格子?
一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
思路:如果预先对所有木板进行处理(求出不同粉刷次数能得到的最大粉刷砖块数)好之后,就是分组背包问题了
而对木板如何预处理呢,答案是线性dp,具体看代码就行
2021/5/22更:重做了一遍,改了代码,之前的太冗杂了@_@
code:
#include<bits/stdc++.h> using namespace std; const int maxn = 1001000; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 1000007; int n, m, t; int dp[55][55]; char s[55][55]; int res[maxn]; int main() { //freopen("test.txt", "r", stdin); scanf("%d%d%d", &n, &m, &t); for (int i = 1; i <= n; i++) { scanf("%s", s[i] + 1); } for (int q = 1; q <= n; q++) { memset(dp, 0, sizeof(dp)); //dp[i][k],这一块板子的前i格粉刷k次能粉刷好的格子数 for (int i = 1; i <= m; i++) { for (int k = 1; k <= i; k++) { int num1 = 0, num2 = 0; for (int j = i; j >= 1; j--) {//把(j-i)粉刷为数字最大的那个颜色 if (s[q][j] == '1') { num1++; } else { num2++; } dp[i][k] = max(dp[i][k], dp[j - 1][k - 1] + max(num1, num2)); } } } for (int j = t; j >= 1; j--) { for (int i = 1; i <= min(m,j); i++) {//从当前板子选择一种粉刷次数来松弛 res[j] = max(res[j], res[j - i] + dp[m][i]); } } /*for (int i = 1; i <= m; i++) {//反过来不对,这样就是用当前板子的所有粉刷次数来松弛,正确是只能选择一种粉刷次数来松弛 for (int j = t; j >= i; j--) { res[j] = max(res[j], res[j - i] + dp[m][i]); } }*/ } cout << res[t] << endl; return 0; }