bzoj2638 黑白染色

Description

 你有一个n*m的矩形,一开始所有格子都是白色,然后给出一个目标状态的矩形,有的地方是白色,有的地方是黑色,你每次可以选择一个连通块(四连通块,且不要求颜色一样)进行染色操作(染成白色或者黑色)。问最少操作次数。

Input

  第一行两个数n,m表示矩形大小。
  接下来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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5532844.html