题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4751
题意:就是问能否将所有人分成两个集合,两集合内部的人都相互认识,注意A认识B,B认识C,C不一定认识A,且A认识B,B未必认识A
思路:构建一张补图,在彼此无边或单向边连接的两点间加双向边,那么这张图必须是二分图(因为如果点染上三种不同颜色,那么便说明至少要三个集合),否则便不存在那样的两个集合
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 200;
int a[maxn][maxn];
int col[maxn];
vector <int> g[maxn];
int n;
int ok(int v, int c)
{
col[v] = c;
for(int i = 0; i < g[v].size(); i++)
{
if(col[g[v][i]] == c)
return 0;
if(col[g[v][i]] == 0 && !ok(g[v][i], -c))
return 0;
}
return 1;
}
void init()
{
for(int i = 0; i <= 100; ++i)
g[i].clear();
memset(a, 1, sizeof(a));
memset(col, 0, sizeof(col));
}
int main()
{
while(~scanf("%d", &n))
{
init();
for(int i = 1; i <= n; i++)
{
while(1)
{
int aa;
scanf("%d", &aa);
if(aa == 0)
break;
a[i][aa] = 0;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = i + 1; j <= n; j++)
{
if(a[i][j] || a[j][i])
{
g[i].push_back(j);
g[j].push_back(i);
}
}
}
int flag = 1;
for(int i = 1; i <= n; i++)
{
if(col[i] == 0)
{
if(!ok(i, 1))
{
flag = 0;
break;
}
}
}
if(flag)
puts("YES");
else
puts("NO");
}
return 0;
}