题解:P12349 [蓝桥杯 2025 省 B 第二场] 翻转硬币
P12349 题解
思路
考虑动态规划。我们可以观察到,硬币翻转只与其上下的硬币是否翻转有关,与左右是否翻转无关,且每一行的硬币的贡献只与其上下行的贡献有关,我们可以考虑每一行的局部最优从而决定全局最优。
状态定义
由于每一行的贡献取决于其上下两行的贡献,所以我们必须枚举到第 dp[i+1][j][k] 记录状态,其中 dp[i][j][k] 中的
转移方程
由于我们知道了
代码思路
根据状态转移方程,枚举每一行四种状态的最大值,最后从最后一行的四种状态中选出最大值输出。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6;
int graph[1010][1010], dp[1010][2][2], n, m;
int dx[4] = {0,0,1,1}, dy[4] = {0,1,0,1};//四种状态
int com(int x, int pre, int now, int nex) //计算在状态约束下当前行的贡献,pre 表示前行约束,now 表示当前行,nex 表示下一行。
{
int res = 0;
for (int r = 1; r <= m; r++){
int t = 0;
if(graph[x][r] == graph[x][r - 1]) t++;
if(graph[x][r] == graph[x][r + 1]) t++;
if(x - 1 > 0)
if(!(now == pre ^ graph[x][r] == graph[x-1][r]))
t++;
if(x + 1 <= n)
if(!(now == nex ^ graph[x][r] == graph[x+1][r]))
t++;
res += t* t;
}
return res;
}
int main()
{
cin >> n >> m;
memset(graph, -1, sizeof(graph));
for(int i = 1; i <= n; i++){ //建图
string t; cin >> t;
for (int j = 1; j <= m; j++)
graph[i][j] = t[j - 1] - '0';
}
for (int i = 0; i < 4; i++) //初始化dp数组
dp[2][dx[i]][dy[i]] = com(1,0,dy[i],dx[i]);
for (int i = 3; i <= n + 1; i++){ //枚举每一行
for (int j = 0; j < 4; j++) //枚举四种状态
dp[i][dx[j]][dy[j]] = max(dp[i-1][dy[j]][0] + com(i-1,0,dy[j],dx[j]), dp[i-1][dy[j]][1] + com(i-1,1,dy[j],dx[j]));
}
cout << max({dp[n + 1][0][0],dp[n + 1][0][1],dp[n + 1][1][0],dp[n + 1][1][1]});
return 0;
}