题意:
在n×m的一个棋盘上,每个格子有一个颜色,你可以任意改变它的颜色,改变一次的代价是1,用最小的代价达到以下条件:
- 相邻格子的颜色均不相同。
- 每行最多只能有2种颜色。
输出最小代价和任意一种涂色方案。
题解:
由于每行只能有两种颜色,而且相邻的颜色不同,所以每行一定是ABABA...的样子。所以直接定义:dp[i][j][k]表示前i行,第i行的第一个颜色为j,第二个颜色为k的最小代价,那么:
dp[i][j][k]=min(dp[i−1][p][q])+cost[i][j][k],1≤p,q≤26 j≠p,k≠q
对于 j=p,k=q的情况令cost = INF即可解决
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 550;
const int MAXM = 550;
const int MAXC = 30;
const int INF = 0x3f3f3f3f;
int N, M;
char color[MAXN][MAXM];
int dp[MAXN][MAXC][MAXC];
int cost[MAXN][MAXC][MAXC];
pair <int, int> pre[MAXN][MAXC][MAXC];
void Init(){
//初始化dp和cost
memset(dp, 0x3f, sizeof dp);
memset(cost, 0x3f, sizeof cost);
for(int i = 1; i <= N; i ++){
for(int j = 1; j <= MAXC; j ++){
for(int k = 1; k <= MAXC; k ++){
if(j == k)
continue;
cost[i][j][k] = 0;
for(int p = 1; p <= M; p += 2)//颜色1
cost[i][j][k] += (color[i][p] != ('a' + j - 1));
for(int p = 2; p <= M; p += 2)//颜色2
cost[i][j][k] += (color[i][p] != ('a' + k - 1));
}
}
}
for(int i = 1; i <= MAXC; i ++)
for(int j = 1; j <= MAXC; j ++)
dp[1][i][j] = cost[1][i][j];
}
//输出方案
void Print(int i, int color1, int color2){
if(i > 1)
Print(i - 1, pre[i][color1][color2]. first, pre[i][color1][color2]. second);
for(int i = 1; i <= M; i ++)
if(i & 1) putchar('a' + color1 - 1);
else putchar('a' + color2 - 1);
putchar('\n');
}
int main(){
scanf("%d %d", &N, &M);
for(int i = 1; i <= N; i ++)
scanf("%s", color[i] + 1);
Init();
for(int i = 1; i <= N; i ++)
for(int j = 1; j <= MAXC; j ++)
for(int k = 1; k <= MAXC; k ++)
for(int p = 1; p <= MAXC; p ++)
for(int q = 1; q <= MAXC; q ++)
if(p != j && q != k)
if(dp[i][j][k] > dp[i - 1][p][q] + cost[i][j][k]){
pre[i][j][k] = make_pair(p, q);
//pre存上一行的颜色
dp[i][j][k] = dp[i - 1][p][q] + cost[i][j][k];
}
int Ans = INF, ci, cj;
for(int i = 1; i <= MAXC; i ++)
for(int j = 1; j <= MAXC; j ++)
if(Ans > dp[N][i][j])
Ans = dp[N][ci = i][cj = j];
printf("%d\n", Ans);
Print(N, ci, cj);
return 0;
}