1. 程式人生 > >2016ACM/ICPC亞洲區大連站-重現賽 A

2016ACM/ICPC亞洲區大連站-重現賽 A

 題目大意:

已知有n個人,他們進行了m場比賽,已知其中有X個好人,Y個壞人。比賽一定是在好人和壞人之間進行的。問是否能夠把n個人劃分成好人和壞人兩個部分

好人和中立人打 中立人變成壞人,壞人和中立人打 中立人變成好人 

做的時候開始發現就是一個二分圖,開始不知道這種方法叫做染色法現在明白了

我們需要進行一下dfs 每次對一個好人搜尋後 也需要對他的對手進行搜尋,如果對手是不同陣營 繼續 ,是同陣營代表出錯,如果未被染色,就染上對立顏色,如果兩個中立人打的話,就對其中隨機一個人染一下色就好了,如果到最後還沒有人被染色,就代表沒法完全構成一個二分圖

 

 

 

 

以下為AC程式碼

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 5000;
vector<int>g[maxn];
int flag[maxn];
int ans;
int n,m,a,b;
void init()
{
	for(int i=1; i<=n; i++)
	{
		g[i].clear();
	}
	memset(flag, 0, sizeof(flag));
	ans=1;
}
void dfs(int u,int pre,int k)
{
    if(!ans) 
	return;
    flag[u]=k;
    for(int i=0; i<g[u].size(); i++)
    {
        int v=g[u][i];
        if(v==pre)
		 continue;
        if(k==1)
        {
            if(flag[v]==1)
            {
                ans=0;
                return ;
            }
            if(flag[v]==0)
            dfs(v,u,-1);
        }
        else
        {
            if(flag[v]==-1)
            {
                ans=0;
                return;
            }
            if(flag[v]==0)
            dfs(v,u,1);
        }
    }
}
int main()
{
	while(~scanf("%d%d%d%d",&n,&m,&a,&b))
	{
		init();
		for(int i=1;i<=m;i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			g[a].push_back(b);
			g[b].push_back(a);
		}
		for(int i=1;i<=a;i++)
		{
			int temp;
			scanf("%d",&temp);
			flag[temp]=1;
		}
		for(int i=1;i<=b;i++)
		{
			int temp;
			scanf("%d",&temp);
			flag[temp]=-1;
		}
		for(int i=1;i<=n;i++)
		{
			if(flag[i]!=0)
			{
				dfs(i,0,flag[i]);
			}
		}
		for(int i=1;i<=n;i++)
		{
			if(flag[i]==0&&g[i].size()!=0)
			{
				dfs(i,0,1);
			}
		}
		for(int i=1;i<=n;i++)
		{
			if(flag[i]==0)
			{
				ans = 0;
				break;
			}
		}
		if(ans)
		printf("YES\n");
		else
		printf("NO\n");
	}
	return 0;
}