A. Graph and String(补图上染色法判二分图)

https://codeforces.com/problemset/problem/623/A


题意:给你一张图,给三个字母a,b,c。图的要求是如果字母相同或者相邻则必须连边,给你一张图,问能不能满足这个条件。满足则输出一种方案。

思路:比较明显的是完全图肯定是能满足的(大不了全a)

考虑到题目中有一个比较核心的连接点b,能连接a和c,所以说如果图里面有度数为n-1的点,那肯定是b,那么把相关的边去掉看剩下的图的情况。这个过程就是建立了一张补图。

然后补图上只有a和c两个字母,根据条件补图上两端点的字母需要不同,所以染色法判定一下二分图。判完之后最后对整张图check一下看看是否存在连线点两端的颜色>=2,存在就NO。否则输出染色的方案。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=600;
typedef long long LL;
vector<LL>g[maxn];//构建补图 
LL ma[maxn][maxn],col[maxn],deg[maxn];
bool flag=1;
void dfs(LL u,LL color)//染色法判定二分图 
{
	col[u]=color;
	for(LL i=0;i<g[u].size();i++){
		LL v=g[u][i];
		if(col[v]==col[u]){
			flag=0;return;
		} 
		if(!col[v]){
			dfs(v,4-color);
		}
	}
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,m;cin>>n>>m;
  for(LL i=1;i<=m;i++){
  	LL x,y;cin>>x>>y;ma[x][y]=ma[y][x]=1;
  	deg[x]++;deg[y]++;
  }
  for(LL i=1;i<=n;i++){
  	for(LL j=1;j<=n;j++){
  		if(i==j) continue;
		if(!ma[i][j]) g[i].push_back(j),g[j].push_back(i);	
	}
  }
  for(LL i=1;i<=n;i++){
  	if(deg[i]==n-1) col[i]=2;//b点染色 
  }
  for(LL i=1;i<=n;i++){
  	 if(!col[i]){
  	 	dfs(i,1);//染a色
		break;	
	 }
  }
  if(flag==0) cout<<"NO"<<endl;
  //check
  else{
  	for(LL i=1;i<=n;i++){
  		for(LL j=1;j<=n;j++){
  			if(i==j)continue;
			if(ma[i][j]&&abs(col[i]-col[j])>=2)
			{
				cout<<"NO"<<endl;return 0;	
			}	
		}
	}
	cout<<"YES"<<endl;
	for(LL i=1;i<=n;i++){
		if(col[i]==1) cout<<"a";
		if(col[i]==2) cout<<"b";
		if(col[i]==3) cout<<"c";
	}
	cout<<endl;
  } 
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108469796