题目大意:
把一块大小为M*N的白木板的某些格子涂成黑色
每次可选一个联通块,全涂白或者全涂黑,问最少涂几次
solution:
(非常巧妙的建图)???
每个点与周围颜色相同的格子连边权为0的边
每个点与周围颜色不同的格子连边权为1的边
求每个点到最远的黑格子的最短路,取min+1就是答案
但实际操作时考虑会有全部是白色
可以是到黑色+1,到白色不+1
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstring>
#include<queue>
#define N 55
#define M 2505
using namespace std;
int n,m,a[N][N],c[N][N],typ[M],num,cnt,head[M],dis[M],ans=0x3f3f3f3f;
char b[N][N];
bool vis[M],flg;
struct EDGE{
int to,nxt,w;
}edge[M*5];//结构体数组开小re了一次···
void add(int x,int y,int z){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
edge[cnt].w=z;
head[x]=cnt;
}
int SPFA(int s){
int res=0;
memset(vis,0,sizeof vis); memset(dis,0x3f,sizeof dis);
queue<int> q;
while(!q.empty()) q.pop();
dis[s]=0,vis[s]=1,q.push(s);
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].w){
dis[v]=dis[u]+edge[i].w;
if(!vis[v]) vis[v]=1,q.push(v);
}
}
vis[u]=0;
}
for(int i=1;i<=num;i++)
if(typ[i]==2) res=max(res,dis[i]+1);
else res=max(res,dis[i]);
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",b[i]+1);
for(int j=1;j<=m;j++){
c[i][j]=++num;
if(b[i][j]=='W') a[i][j]=1,typ[num]=1;
else a[i][j]=2,typ[num]=2,flg=true;
}
}
if(!flg) {printf("0\n");return 0;} //这个特判可加可不加吧···
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int x=c[i][j];
if(a[i-1][j])
{if(a[i-1][j]!=a[i][j]) add(x,c[i-1][j],1);
else add(x,c[i-1][j],0);}
if(a[i+1][j])
{if(a[i+1][j]!=a[i][j]) add(x,c[i+1][j],1);
else add(x,c[i+1][j],0);}
if(a[i][j-1])
{if(a[i][j-1]!=a[i][j]) add(x,c[i][j-1],1);
else add(x,c[i][j-1],0);}
if(a[i][j+1])
{if(a[i][j+1]!=a[i][j]) add(x,c[i][j+1],1);
else add(x,c[i][j+1],0);}
}
for(int i=1;i<=num;i++) ans=min(ans,SPFA(i));
printf("%d\n",ans);
return 0;
}