啊很久没写博客了
晚上熬夜熬太晚了导致下午很颓废,写个博客休息一下
进入正题……

首先题目描述说一行最多有两种颜色,而且相邻两格颜色不同,于是可以得出每一行都是由两个不同的字符交替组成的(然后我们就枚举他)
首先定义dp[i][j][k]表示第i行的第一个和第二个字符分别是j和k时最小花费,price[i][j][k]为从原状态转移到第一个和第二个字符分别为j和k时的花费,price是可以被预处理的
然后可以得到状态转换方程dp[i][j][k]=min(dp[i][j][k],dp[i-1][y][u]+price[i][j][k])(其中y,u为i-1时的j,k)
然后第一小问就做完了
然后是第二小问
第二小问因为我们求出了dp[n][i][j]和price[n][i][j],然后我们就可以倒退
然后这个题我们就做完了
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
long long n,m;
char c;
long long shu[505][505],price[505][30][30],dp[505][30][30];
void shuchu(long long wz,long long l,long long r)
{
if(wz==0)
{
return;
}
long long bj=0,ll=dp[wz][l][r]-price[wz][l][r];
for(int i=0;i<26;i++)
{
if(bj==1)
{
break;
}
if(i==l)
{
continue;
}
for(int j=0;j<26;j++)
{
if(j==r)
{
continue;
}
if(dp[wz-1][i][j]==ll)
{
shuchu(wz-1,i,j);
bj=1;
break;
}
}
}
for(int i=1;i<=m;i++)
{
if(i%2==1)
{
cout<<(char)(l+'a');
}else
{
cout<<(char)(r+'a');
}
}
cout<<endl;
return;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>c;
shu[i][j]=(c-'0')-49;
}
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<26;j++)
{
for(int k=0;k<26;k++)
{
dp[i][j][k]=9999999999;
for(int wz=1;wz<=m;wz++)
{
if((wz%2==1)&&shu[i][wz]!=j)
{
price[i][j][k]++;
}else if((wz%2==0)&&shu[i][wz]!=k)
{
price[i][j][k]++;
}
}
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<26;j++)
{
for(int k=0;k<26;k++)
{
if(j==k)continue;
for(int y=0;y<26;y++)
{
if(y==j)continue;
for(int u=0;u<26;u++)
{
if(u==y||u==k)continue;
dp[i][j][k]=min(dp[i][j][k],dp[i-1][y][u]+price[i][j][k]);
}
}
}
}
}
long long ans=9999999999999,l=0,r=0;
for(int i=0;i<26;i++)
{
for(int j=0;j<26;j++)
{
if(dp[n][i][j]<ans)
{
l=i;
r=j;
ans=dp[n][i][j];
}
}
}
printf("%lld
",ans);
shuchu(n,l,r);
return 0;
}
//看着挺容易的……
//因为每行最多两个字符而且相邻不能一致,所以必然是交替出现
//那就枚举……枚举这一行的两个字母和上一行的两个字母,dp[i][j][k]表示第i行,第一个字母是j第二个字母是k时的最小代价
//显而易见1 dp[i][j][k]=min(dp[i][j][k],dp[i-1][y][u]+price[i-1][y][u])(price[i][j][k]为将原序列转化成上面表述的代价)
//显而易见1.5 price可以预处理
//倒叙输出
(祝大家明天端午节快乐)