2007-2008 Winter Petrozavodsk Camp, Andrew Stankevich Contest 30-E - New Mayors - 二分图染色 (BFS+DFS)

http://codeforces.com/gym/100345/attachments

-E - New Mayors 

题意:

给一无向图和三种颜色,顶点n(n<=500),边m,

告诉你这个图里,对于任意节点U, 定义N【u】为u的所有直接儿子节点的集合,并且集合中任意两个点可以通过N【u】中的点互相到达(不经过U)。

现在让你用三种颜色染图,规定一条边两端颜色不可相等。


如果是直接用三个颜色去染图 复杂度感人。。。


由于题目的图有一个性质【即u的所有直接儿子节点是联通的】(据此可以知道儿子们的二分图染色方案唯一)

那么我们只看u以及 u的直接儿子:

首先u和所有儿子相连,必然【U占一种颜色,所有儿子共用2种颜色】,如果儿子们用了三种颜色,那么U必然会和一个儿子冲突。  因此,我们把U拔出来,【作为root】,把U的儿子们构成的图看作一个新的子图,用这个图去跑二分图染色 ,如果染色失败,则不存在合法方案,否则 U及其儿子们的染色方案目前是合法的。

【然后从U的每个作为新的root,去染色】

二分图染色部分我们用一个dfs做

而不断选出新的root来去染色这部分我们可以用一个队列,每次把root的儿子都放进队列,然后不断从队列取出root,当队列空则 另找一个新的root放进队列【整个图可能非联通】

注意“【每次跑二分图染色的节点只有U的直接儿子节点】


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;}

vector<int> mp[600];		//邻接矩阵
int expand[600];			//表示是否进入过队列
int col[600];				//节点颜色
int vaild[600];				//表示参与二分图染色的节点
int vis[600];				//标记每次跑二分图染色时该节点是否访问过
int dfs(int x,int rt)
{
	int i; 				 
	for (i=0;i<mp[x].size();i++)
	{
		int v=mp[x][i]; 
		if (!vaild[v])continue;
		if (col[v]&&col[v]!=6-col[rt]-col[x] ) return 0; //涂过色且颜色与当前方案冲突
		if (!vis[v])	//如果在本次染色过程未访问过,则dfs进入
		{
			vis[v]=1;	 
			if (!col[v]) 
				col[v]=6-col[rt]-col[x] ; //无色则染色
			if (dfs(v,rt)==0) return 0;    //递归进入
		}
	}
	return 1;
}
queue<int >q;	//作为染色root节点

int main()
{ 
 	freopen( "mayors.in","r",stdin ); // scanf 从1.txt输入
	freopen( "mayors.out","w",stdout );  //printf输出到1.tx
	int n,m; 
	cin>>n>>m;
	int x,y,i;
	for (i=1;i<=n;i++) mp[i].clear();
	for (i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		mp[x].push_back(y);
		mp[y].push_back(x);
	} 
	int flag=0;   
	int idx=1;
	while (!q.empty()||idx<=n)
	{
		if (q.empty())  //队列已无可扩节点,寻找新的root 
		for (;idx<=n;idx++)
		{
			if (expand[idx]) continue;//如果已进过队列,则忽略
			q.push(idx);
			col[idx]=1;				//颜色涂1
			expand[idx]=1;			//表示进过队列
			break;
		}
		if (q.empty())break;
		int rt=q.front();q.pop();
	//	printf("%d\n",q.size());
		if (mp[rt].size()==0) continue;
		int start=mp[rt][0];			//任取一个start节点
		memset(vaild,0,sizeof (vaild)); 
		memset(vis,0,sizeof (vis));	
		for (i=0;i<mp[rt].size();i++)
		{
			int v=mp[rt][i];
			vaild[v]=1;				//表示该节点参与本次二分图染色
			if (!expand[v])			//加入队列
			q.push(v);
			expand[v]=1;	
			if (col[v]) start=v;		//如果该节点颜色确定,则从它出发染色
		}
		if (!col[start]) col[start]=2;		//如果全部节点无颜色,则任意涂个2或3
		vis[start]=1;					 
		if (!dfs(start,rt))		
		{ flag=1;break;}			//染色失败,不存在合法方案
	}


	if (flag) {printf("Plan failed\n");return 0;}
	
			printf("Plan OK\n"); 
				for (i=1;i<=n;i++)
				{	 
					if (col[i]==1)
						printf("G");
					else if (col[i]==2)
						printf("B");
					else printf("R");
				}
				printf("\n");
				
				return 0;
				
} 


你可能感兴趣的:(2007-2008 Winter Petrozavodsk Camp, Andrew Stankevich Contest 30-E - New Mayors - 二分图染色 (BFS+DFS))