ZOJ 3781-缩点+bfs模拟

http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3781


题意:


在n*m矩阵的图定义连通区域为x值或y值相同且颜色相同的连通,连通具有传递性


每次可以把一个连通区域颜色反转(O变X,X变O)


问把所有块的颜色变为X最小的步数


思路:

乍一看,翻开随便一个点会影响一大片联通块翻转,实际上只是吓人的,我们其实可以把每个联通块看成一个点。

把原图处理一下,所有在一个联通块的点直接看成一个点,相邻的不同联通块显然颜色不同(否则可以可并为一个块嘛!)   那么我们直接暴力枚举,以任一个联通块作为起点,显然的话,每翻一个联通块,就会把周围所有的联通块并入,形成一个大的联通块  。。直接模拟 就好


初始化联通块并编号,例如从联通块i开始,每一次,把当前联通块周围的所有联通块编号标记为1,然后丢进队列,每次再从队列取出联通块编号,把其周围联通块合并。。。。bfs乱搞就ac了

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const double pi=acos(-1.0);
double eps=0.000001; 
int min(int a,int b)
{return a<b?a:b;} 
int max(int a,int b)
{return a>b?a:b;}

int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
char mp[45][45];
int id=1;
int vis[45][45];
int flag;
int check[45][45];
int n,m;
struct node
{
	int x,y,step;
	node(int a=0,int b=0,int c=0){x=a,y=b;step=c;}
};
vector<node > node_in_col[40*40+5];
vector <int> sb[40*40+5];
void dfs(int x,int y )
{
	int i,j;
	if (vis[x][y]) return ;
	flag=1;
	vis[x][y]=id;
	node_in_col[id].push_back(node(x,y));
	for (i=0;i<4;i++)
	{
		int xx=x+dx[i];
		int yy=y+dy[i];
		if (!(xx>=1&&xx<=n&&yy>=1&&yy<=m))continue;
		if (mp[xx][yy]!=mp[x][y]) continue;
		dfs(xx,yy);
	}
}
int col[40*40+5];
struct bf
{
	int t,c;
	bf(int a,int b){c=a;t=b;}
};
int solve(int cc)
{ 
	memset(col,0,sizeof(col));
	int ret=0;
	queue<bf>q;
	int i,j; 
	bf st(cc,0);
	q.push(st);
		col[cc]=1; 
	while(!q.empty())
	{
		bf tp=q.front();q.pop();
		ret=max(ret,tp.t);
		int tmp=tp.c;
		for (int i=0;i<sb[tmp].size();i++)
		{
		int tt=sb[tmp][i];
			if (col[tt]) continue;
			q.push(bf(tt,tp.t+1) );
			col[tt]=1;  
		}
	}  
		return ret;
}
	int main()
	{
		
		int t;cin>>t;
		while(t--)
		{
			memset(vis,0,sizeof vis); 
			cin>>n>>m;
			int i,j;
			for (i=1;i<=n;i++)
				scanf("%s",mp[i]+1);

			for (i=1;i<=n*m;i++)
				sb[i].clear(),node_in_col[i].clear();

			id=1;
			for (i=1;i<=n;i++)
			{
				for (j=1;j<=m;j++)
				{
					flag=0;
					dfs(i,j );
					if (flag) id++;
				}
			}	

			/*for (i=1;i<=n;i++)
			{
				for (j=1;j<=m;j++)
				{
					printf("%2d",vis[i][j]);
				}
				printf("\n");
		}*/
			for (i=1;i<id;i++)
			{
				for (j=0;j<node_in_col[i].size();j++)
				{
					int x=node_in_col[i][j].x;
					int y=node_in_col[i][j].y;
					for (int k=0;k<4;k++)
					{
						int xx=x+dx[k];
						int yy=y+dy[k];
						if( !(xx>=1&&xx<=n&&yy>=1&&yy<=m))continue;
						sb[i].push_back(vis[xx][yy]);
					}
				}
			}
		/*	printf("%d\n",node_in_col[4].size());
			for (j=0;j<sb[4].size();j++)
				printf("%d  ",sb[4][j]);
*/
			int minn=40*40+1;
			for (i=1;i<id;i++)
minn=min(minn,solve(i));
		  
			printf("%d\n",minn);
		} 
		
		
		return 0;
		
	}


你可能感兴趣的:(ZOJ 3781-缩点+bfs模拟)