题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3478
思路分析:该问题需要求是否存在某一个时刻,thief可能存在图中没一个点;将该问题转换为图论问题即为判断该图是否为一个连通图且不为二分图;
(1)二分图的性质:对于无向图G=(V, E),如果可以将图中的点划分为两个不相交的点集X与Y = V - X(V为点集),使得图中所有的边邻接的两个点分别存在集合X与集合Y中,则称该图G为二分图;
(2) 二分图判定算法:二分图一种判定方法是给图中的每一个点着黑色或者白色,如果图中每条边邻接的两个点的颜色不同,则该图为二分图,所以非联通的图也可以是二分图,即一个无向图是二分图当且仅当其每个联通分量都是二分图;二分图判定算法使用dfs搜索:选定一个起始结点并着以某一种颜色,从该起始结点出发,与其邻接的点如果已经着色并且颜色与该结点相同,则不为二分图,如果与其邻接的点没有着色,则对该点着以不同的颜色,如此处理直到所有的点被着色成功则该结点所在的联通分量为二分图;需要注意的是图中可能有多个联通分量;
代码如下:
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std; const int MAX_N = + ;
vector<int> G[MAX_N];
int fa[MAX_N], color[MAX_N]; void Init()
{
for (int i = ; i < MAX_N; ++i)
{
fa[i] = i;
G[i].clear( );
}
memset(color, , sizeof(color));
} int Find(int v)
{
if (fa[v] == v)
return v;
else
return fa[v] = Find(fa[v]);
} int Union(int a, int b)
{
int fa_a = Find(a);
int fa_b = Find(b); if (fa_a == fa_b)
return -;
else if (fa_a > fa_b)
fa[fa_b] = fa_a;
else
fa[fa_a] = fa_b;
return ;
} bool BiPartite(int u)
{
for (int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
if (color[u] == color[v])
return false;
if (!color[v])
{
color[v] = - color[u];
if (!BiPartite(v))
return false;
}
}
return true;
} int main()
{
int test_case, ver_1, ver_2;
int ver_num, road_num, start, case_id = ; scanf("%d", &test_case);
while (test_case--)
{
Init();
scanf("%d %d %d", &ver_num, &road_num, &start);
for (int i = ; i < road_num; ++i)
{
scanf("%d %d", &ver_1, &ver_2);
G[ver_1].push_back(ver_2);
G[ver_2].push_back(ver_1);
Union(ver_1, ver_2);
} int set_count = ;
for (int i = ; i < ver_num; ++i)
{
if (fa[i] == i)
set_count++;
if (set_count > )
break;
}
printf("Case %d: ", ++case_id);
color[start] = ;
if (!BiPartite(start) && set_count == )
printf("YES\n");
else
printf("NO\n");
}
return ;
}