[SCOI2009]粉刷匠 DP)

[SCOI2009]粉刷匠

题目描述:
windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。
windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。
如果windy只能粉刷 T 次,他最多能正确粉刷多少格子?
一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
输入描述:
第一行包含三个整数,N M T。
接下来有N行,每行一个长度为M的字符串,'0’表示红色,'1’表示蓝色。
30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。
100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 .
输出描述:
输出包含一个整数,最多能正确粉刷的格子数

思路:
一看数据范围, 肯定是个 dp 了
但是这个数据范围做不了状压 dp
考虑普通的 dp
这个问题的难点在于他是二维的情况(多个木块)
那么如果是一维的情况怎么做呢?我们先考虑一下
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示第 i 个木板粉刷 j次涂了前面 k 个格子的正确格子数
因为只有两种颜色, 对于某一块木板, 我们可以维护一个前缀和 s u m [ i ] [ j ] sum[i][j] sum[i][j] 表示第 i i i 个木板的第 j j j 个格子前蓝色格子的数目
对于单个木板有 f [ i ] [ j ] [ k ] = m a x ( f [ i ] [ j ] [ k ] , f [ i ] [ j − 1 ] [ l ] + m a x ( s u m [ i ] [ k ] − s u m [ i ] [ l ] , k − l − s u m [ i ] [ k ] + s u m [ i ] [ l ] ) f[i][j][k] = max(f[i][j][k], f[i][j - 1][l] + max(sum[i][k] - sum[i][l], k - l - sum[i][k] + sum[i][l]) f[i][j][k]=max(f[i][j][k],f[i][j1][l]+max(sum[i][k]sum[i][l],klsum[i][k]+sum[i][l])
表示对第 i i i 块木板涂了 j j j 次, 此时到第 k k k 个位置可以从第 i i i 块木板的涂了 j − 1 j - 1 j1次的第 l l l 个位置转移过来
对于要么取蓝色, 要么取红色, 我们取个 max 即可, s u m [ i ] [ k ] − s u m [ i ] [ l ] 是 [ l , k ] 的 蓝 色 格 子 k − l − s u m [ i ] [ k ] + s u m [ i ] [ l ] sum[i][k] - sum[i][l]是 [l, k] 的蓝色格子 k - l - sum[i][k] + sum[i][l] sum[i][k]sum[i][l][l,k]klsum[i][k]+sum[i][l] [ l , k ] [l, k] [l,k] 的红色格子
此时再考虑多个木板情况
显然有 d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j − k ] + f [ i ] [ k ] [ m ] ) dp[i][j] = max(dp[i][j], dp[i - 1][j - k] + f[i][k][m]) dp[i][j]=max(dp[i][j],dp[i1][jk]+f[i][k][m])
表示到第 i 个木板涂了 j 次可以从 第i - 1个木板涂了 j - k 次转移过来

Code:

#include<bits/stdc++.h>
using namespace std;
const int N = 55;

int sum[N][N];
int f[N][N][N];  //对于第i块板,粉刷j次前k个格子得到的最多正确粉刷格子 
int dp[N][N*50];  //前i块板子,粉刷j次获得的最多正确粉刷格子 

int main()
{
    int n,m,t;
    cin>>n>>m>>t;
    string s;
    for(int i=1;i<=n;i++){
    	cin>>s;
    	for(int j=0;j<m;j++)
    	sum[i][j+1] = sum[i][j] + (s[j]-'0');
	}
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    		for(int k=1;k<=m;k++)
    			for(int l=j-1;l<k;l++)
    			f[i][j][k] = max(f[i][j][k],f[i][j-1][l]+max(sum[i][k]-sum[i][l],k-l-sum[i][k]+sum[i][l]));
    int ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=t;j++)
			for(int k=0;k<=min(j,m);k++){
				dp[i][j] = max(dp[i][j],dp[i-1][j-k]+f[i][k][m]);
				ans = max(dp[i][j],ans);
			}
    cout<<ans<<"\n";
    return 0;
}

参考博客:https://blog.nowcoder.net/n/24993fefbc7e4c7f8b439891af77d701

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 我行我“速” 设计师:Amelia_0503 返回首页