Description
你有一个n*m的矩形,一开始所有格子都是白色,然后给出一个目标状态的矩形,有的地方是白色,有的地方是黑色,你每次可以选择一个连通块(四连通块,且不要求颜色一样)进行染色操作(染成白色或者黑色)。问最少操作次数。
Input
第一行两个数n,m表示矩形大小。
接下来n行描述目标状态,每行m个字符,’W’表示白色,’B’表示黑色。
接下来n行描述目标状态,每行m个字符,’W’表示白色,’B’表示黑色。
Output
一行一个整数表示操作数。
将同色方块缩点建出二分图
枚举每个点为根求bfs树
按深度从深至浅顺序染色
树的深度-(最深叶节点为白色?1:0)为以这个点为中心染色的最少操作次数
#include<cstdio> int n,m; char s[56][56],col[3000]; int id[56][56],idp=0; int es[20050],enx[20050],e0[3000],l[3000],q[3000],ep=2,ql,qr,mx,ans; void dfs(int x,int y,int c){ if(id[x][y]||s[x][y]!=c)return; id[x][y]=idp; dfs(x-1,y,c); dfs(x+1,y,c); dfs(x,y-1,c); dfs(x,y+1,c); } void adde(int a,int b){ es[ep]=b;enx[ep]=e0[a];e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } int main(){ scanf("%d%d",&n,&m); ans=n*m; for(int i=1;i<=n;i++)scanf("%s",s[i]+1); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(!id[i][j]){ col[++idp]=s[i][j]; dfs(i,j,col[idp]); } } } for(int i=1;i<=n;i++){ for(int j=1;j<m;j++){ if(id[i][j]!=id[i][j+1])adde(id[i][j],id[i][j+1]); } } for(int i=1;i<n;i++){ for(int j=1;j<=m;j++){ if(id[i][j]!=id[i+1][j])adde(id[i][j],id[i+1][j]); } } for(int i=1;i<=idp;i++){ for(int j=1;j<=idp;j++)l[j]=0; l[i]=1; ql=qr=mx=0; q[qr++]=i; while(ql!=qr){ int w=q[ql++]; if(l[w]>mx)mx=l[w]; for(int e=e0[w];e;e=enx[e]){ int u=es[e]; if(!l[u]){ l[u]=l[w]+1; q[qr++]=u; } } } if(col[i]=='W'&&(mx&1))--mx; if(col[i]=='B'&&!(mx&1))--mx; if(mx<ans)ans=mx; } printf("%d\n",ans); return 0; }