枚举,$BFS$,连通块缩点。
可以枚举一开始染哪个位置,然后逐层往外染色,看最多需要多少操作次数,也就是算最短距离。连通块缩点之后可以保证是一个黑白相间的图,且每条边的费用均为$1$,$BFS$即可。
#include<cstdio> #include<queue> #include<algorithm> #include<vector> #include<cstring> using namespace std; int T,n,m; char s[50][50]; int Belong[50][50],block,use[50*50]; int dx[]={0,0,-1,1}; int dy[]={1,-1,0,0}; int h[50*50]; struct Edge { int from,to,nx; }e[100000]; int sz; bool ok(int x,int y) { if(x>=0&&x<n&&y>=0&&y<m) return 1; return 0; } void dfs(int x,int y) { Belong[x][y]=block; if(ok(x-1,y)&&s[x][y]==s[x-1][y]&&Belong[x-1][y]==0) dfs(x-1,y); if(ok(x+1,y)&&s[x][y]==s[x+1][y]&&Belong[x+1][y]==0) dfs(x+1,y); if(ok(x,y-1)&&s[x][y]==s[x][y-1]&&Belong[x][y-1]==0) dfs(x,y-1); if(ok(x,y+1)&&s[x][y]==s[x][y+1]&&Belong[x][y+1]==0) dfs(x,y+1); } void add(int x,int y) { e[sz].from=x; e[sz].to=y; e[sz].nx = h[x]; h[x]=sz++; } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%s",s[i]); memset(Belong,block=0,sizeof Belong); sz=0; memset(h,0xff,sizeof(h)); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(Belong[i][j]) continue; block++; dfs(i,j); } } for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { for(int k=0;k<4;k++) { int x=i+dx[k]; int y=j+dy[k]; if(!ok(x,y)) continue; if(Belong[i][j]==Belong[x][y]) continue; add(Belong[i][j],Belong[x][y]); } } } int ans=0x7fffffff; for(int i=1;i<=block;i++) { memset(use,-1,sizeof(use)); int mx=0; use[i]=0; queue<int>q; q.push(i); while(!q.empty()) { int x=q.front(); q.pop(); for(int j=h[x];j!=-1;j=e[j].nx) { int y=e[j].to; if(use[y]!=-1) continue; use[y]=use[x]+1; mx=max(use[y],mx); q.push(y); } } ans=min(mx,ans); } printf("%d\n",ans); } return 0; }