如果出现遍历图中的某个点都是在奇数时刻或者偶数时刻,那么小偷的藏点就是根据时间判定在某些的奇数点和偶数点了。

如果图出现奇数的环,即:有一个环由奇数个点组成,那么环中的某个点在奇数和偶数时刻都能到达(可以画图试试)。其实奇数环导致小偷藏点无规律的最大原因是:

在遍历最后奇数环的两个(必定是两个)未遍历点的时候他们是同奇(偶)的,然而还有一条边直接相连。导致在下一时刻,那两个点又可以同时变成偶(奇)。如果在回溯遍历的话,就会出现整张图在奇数时刻或者偶数时刻都能到达。

无向图G为二部图的充分必要条件是:
G至少有两个顶点,且其所有回路的长度均为偶数。

如果我们把图中奇数时刻能够到达的点归到X集合,偶数能到点归到Y集合,那么如果图中出现相同集合的点有
边相连,那么就不满足二分图的性质,即可输出YES,如果原图可二分图话,答案就是NO了。

然后就是经典的二分图判定。

CODE:

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int MAXN = 100010;
const int MAXM = 500010;

struct Edge
{
    int v, next;
}edge[MAXM];

int n, m, s;
int cnt;

int first[MAXN];
bool color[MAXN], vis[MAXN];

void init()
{
    cnt = 0;
    memset(vis, 0sizeof(vis));
    memset(color, 0sizeof(color));
    memset(first, -1sizeof(first));
}

void read_graph(int u, int v)
{
    edge[cnt].v = v;
    edge[cnt].next = first[u], first[u] = cnt++;
}

int find(int u)
{
    for(int e = first[u]; e != -1; e = edge[e].next)
    {
        int v = edge[e].v;
        if(!vis[v])
        {
            vis[v] = 1;
            color[v] = !color[u];
            find(v);
        }
        else if(color[u] == color[v])    return false;
    }
    return true;
}

int main()
{
    int T, times = 0;
    scanf("%d", &T);
    while(T--)
    {
        init();
        scanf("%d%d%d", &n, &m, &s);
        while(m--)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            read_graph(u, v);
            read_graph(v, u);
        }
        printf("Case %d: ", ++times);
        color[s] = 1;
        vis[s] = 1;
        printf(find(s)?"NO\n":"YES\n");
    }
    return 0;
}


 

posted on 2012-11-02 17:15  有间博客  阅读(360)  评论(0编辑  收藏  举报