[bzoj2638]黑白染色——思维题+最短路 大佬们的博客 Some Links

版权声明:欢迎大家转载,转载请标明出处。 https://blog.csdn.net/ylsoi/article/details/82938642

题目大意:

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

思路:

可以证明每一次操作的范围都是上一次操作的子集,并且颜色与上一次相反(但是我不会证)。
于是我们可以把黑色连通块和白色连通块之间互相连边,这样就形成了一个图,我们枚举最后进行操作的那个区域,那么可以看成是以当前这个连通块为中心,不断地将最外围的连通块染上题目要求的颜色。
于是我们只需要枚举最后的区域 S i S_i ,求出每个连通块 T j T_j 和这个区域 S i S_i 的最短距离(也就是这个连通块 T j T_j 的操作次数),然后取所有的 T j T_j 的距离最大值为当前中心 S i S_i 的操作次数 v a l i val_i ,最后求出 min ( v a l i ) \min(val_i) 即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
typedef long long ll;

using namespace std;

void File(){
	freopen("bzoj2638.in","r",stdin);
	freopen("bzoj2638.out","w",stdout);
}

template<typename T>void read(T &_){
	T __=0,mul=1; char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')mul=-1;
		ch=getchar();
	}
	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
	_=__*mul;
}

const int maxn=50+10;
const int maxm=2500+10;
int n,m,a[maxn][maxn],id[maxn][maxn];
int dx[5]={0,1,0,-1,0};
int dy[5]={0,0,1,0,-1};
int col[maxm],beg[maxm],las[maxm<<2],to[maxm<<2],cnte;
int dis[maxm],ans=0x3f3f3f3f;
bool vis[maxm];

bool judge(int x,int y){
	return x>=1 && x<=n && y>=1 && y<=m;
}

void add(int u,int v){
	las[++cnte]=beg[u];beg[u]=cnte;to[cnte]=v;
}

queue<int>qu;
int bfs(int ss){
	int ret=0;
	memset(vis,0,sizeof(vis));
	memset(dis,63,sizeof(dis));
	qu.push(ss); vis[ss]=1; dis[ss]=0;
	while(!qu.empty()){
		int u=qu.front(); qu.pop(); vis[u]=0;
		for(int i=beg[u];i;i=las[i]){
			int d=dis[u]+(col[u]!=col[to[i]]);
			if(d<dis[to[i]]){
				dis[to[i]]=d;
				if(!vis[to[i]]){
					vis[to[i]]=1;
					qu.push(to[i]);
				}
			}
		}
	}
	REP(i,1,n*m)if(col[i])ret=max(ret,dis[i]+1);
	return ret;
}

void init(){
	read(n); read(m);
	char s[maxn];
	REP(i,1,n){
		scanf("%s",s+1);
		REP(j,1,m)a[i][j]=(s[j]=='B');
	}
	REP(i,1,n)REP(j,1,m)id[i][j]=(i-1)*m+j;
	REP(i,1,n)REP(j,1,m){
		col[id[i][j]]=a[i][j];
		REP(k,1,4){
			int x=i+dx[k],y=j+dy[k];
			if(!judge(x,y))continue;
			add(id[i][j],id[x][y]);
		}
	}
}

int main(){
	File();
	init();
	REP(i,1,n*m)ans=min(ans,bfs(i));
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/82938642