【DP】E.矩阵游戏

题目来源

2023第五届CCPC河南省赛赛题 :E.矩阵游戏
cf链接 :2023 CCPC Henan Provincial Collegiate Programming Contest E.矩阵游戏

【DP】E.矩阵游戏_第1张图片

样例

text1输入:

1
3 3 1
000
001
?00

text1输出:

1

text2输入:

1
3 3 2
000
001
??0

text2输出:

2

思路

  1. 先考虑三维,前两维 i, j 表示行列,第三维表示剩余替换?的次数,显然dp[500][500][1000]会爆,则要考虑优化维度。
  2. 优化参考01背包问题的优化,去掉第一维,枚举x的时候倒序。
  3. 千万不要忘了先对第一个数做处理,mp(1, 1) = ‘1’,mp(1, 1) = ‘?’ && x 两种情况需要分别将dp数组的对应状态初始化为1。
  4. 由于是多组测试用例,在开始时重置dp数组不然会出现莫名其妙的错误。

AC代码

#include
#pragma GCC optimize(2)
#define INF 0x3f3f3f3f

using namespace std;

int n, m, x;
int dp[510][1010];
char mp[510][510];

void solve()
{
	//读入
	cin >> n >> m >> x;
	for(int i = 1; i <= n; i ++)	
		for(int j = 1; j <= m; j ++)
			cin >> mp[i][j];
			
	//有多组测试用例,一定要重置dp数组
	for(int i = 0; i <= m; i ++)	
		for(int j = 0; j <= x; j ++)
			dp[i][j] = 0;

	//对(1, 1)处理
	if(mp[1][1] == '1')
		for(int i = 0; i <= x; i ++)
			dp[1][i] = 1;
	if(mp[1][1] == '?')
		for(int i = 1; i <= x; i ++)
			dp[1][i] = 1;
	
	for(int i = 1; i <= n; i ++) {			//1 ~ n
		for(int j = 1; j <= m; j ++) {		//1 ~ m
			for(int k = x; k >= 0; k --) {	//key倒序枚举 x ~ 0 
				if(mp[i][j] == '1')		//当前点是 1 
				{
					if(i - 1 > 0)
						dp[j][k] = dp[j][k] + 1;	//dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j][k] + 1);
					if(j - 1 > 0)
						dp[j][k] = max(dp[j][k], dp[j - 1][k] + 1);	//dp[i][j][k] = max(dp[i][j][k], dp[i][j - 1][k] + 1);
				}
				else if(mp[i][j] == '0')//当前点是 0  
				{
//					if(i - 1 > 0)
//						dp[j][k] = dp[j][k];	//dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j][k]);
					if(j - 1 > 0)
						dp[j][k] = max(dp[j][k], dp[j - 1][k]);		//dp[i][j][k] = max(dp[i][j][k], dp[i][j - 1][k]);
				}
				else if(mp[i][j] == '?')//当前是 ? 
				{
					if(i - 1 > 0 && k)
						dp[j][k] = max(dp[j][k], dp[j][k - 1] + 1);		//dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j][k - 1] + 1);
					if(j - 1 > 0 && k)
						dp[j][k] = max(dp[j][k], dp[j - 1][k - 1] + 1);	//dp[i][j][k] = max(dp[i][j][k], dp[i][j - 1][k - 1] + 1);
						
					// 当k为0,同当前点是‘0’一样处理
					if(j - 1 > 0 && !k)		
						dp[j][k] = max(dp[j][k], dp[j - 1][k]);			//dp[i][j][k] = max(dp[i][j][k], dp[i][j - 1][k]);
				}
			}
		}
	}
	
	//得到1最多的状态(即答案)一定在走到右下角的所有状态中,第二维0 ~ x中取max
	int ans = 0;
	for(int i = 0; i <= x; i ++) ans = max(ans, dp[m][i]);
	
	cout << ans << endl;
}

int main()
{
	int _ = 1;
	cin >> _;
	while(_--) solve();
	return 0;
}

你可能感兴趣的:(算法竞赛,矩阵,算法,动态规划)