题目大意:
已知有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;
}