hdu 3478 Catch 二分图染色
题目链接
题意
小偷逃跑,从某个点出发,每下一个时刻能够跑到与当前点相邻的点。
问是否存在某一个时刻,小偷可能在图中的任意一个点出现。
思路
结论
如果该图为连通图且不为二分图,则可能,否则不可能。
原因
首先显见图需要连通。
下证:小偷可能在图中任意一个点出现当且仅当该连通图不为二分图。
必要性:如果该图是个二分图,那么将图中所有点染成白点和黑点。假设小偷起始时刻在白点,那么下一时刻必然在黑点,下下时刻必然在白点……即每个时刻小偷只可能在白点或黑点,即不可能出现在图中任意一个点。
充分性:如果该图不为二分图,那么就存在相同颜色的点之间有边,不妨设为白点。于是就存在某个时刻,小偷能够从白点跑到白点与黑点。又因为图连通,从此往后足够长的时间,小偷就可能出现在图中任意一个点了。
具体实现
考虑到同时要判断连通图与二分图,采取\(dfs\)的方式,一次即可.
Code
#include <bits/stdc++.h>
#define maxm 500010
#define maxn 100010
using namespace std;
typedef long long LL;
struct Edge {
int to, ne;
Edge(int _to=0, int _ne=0) : to(_to), ne(_ne) {}
}edge[maxm * 2];
int tot, ne[maxn], col[maxn];
void add(int u, int v) {
edge[tot] = Edge(v, ne[u]);
ne[u] = tot++;
}
bool flag;
void dfs(int u, int c) {
col[u] = c;
for (int i = ne[u]; ~i; i = edge[i].ne) {
int v = edge[i].to;
if (col[v]==-1) dfs(v, !c);
else if (col[v] != !c) flag=true;
}
}
int kas;
void work() {
printf("Case %d: ", ++kas);
int n, m, x;
flag = tot = 0; memset(ne, -1, sizeof(ne)); memset(col, -1, sizeof(col));
scanf("%d%d%d", &n, &m, &x);
for (int i = 0; i < m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
add(u, v); add(v, u);
}
dfs(x, 0);
for (int i = 0; i < n; ++i) if (col[i] == -1) { printf("NO\n"); return; }
if (flag) printf("YES\n");
else printf("NO\n");
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}