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
"); return; }
    if (flag) printf("YES
");
    else printf("NO
");
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) work();
    return 0;
}

原文地址:https://www.cnblogs.com/kkkkahlua/p/7660024.html