Hdu5215 Cycle

Cycle

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 955    Accepted Submission(s): 284

Problem Description
Ery is interested in graph theory, today he ask BrotherK a problem about it: Given you a undirected graph with N vertexes and M edges, you can select a vertex as your starting point, then you need to walk in the graph along edges. However, you can't pass a edge more than once, even opposite direction is forbidden. At the end, you should come back to the starting point. Assume you has passed X edges, there are two questions:

Question 1: Can X be a odd number ?

Question 2: Can X be a even number ?

(note: you must walk, so X can't be 0)
 
Input
The first line contains a single integer T, indicating the number of test cases.

Each test case begins with two integer N, M, indicating the number of vertexes and the number of edges. Following M lines, each line contains two integers Ui, Vi, indicating there are a edge between vertex Ui and vertex Vi.

T is about 30

1  N  100000

0  M  300000

1  Ui,Vi  N

Ui will not equal to Vi

There is at most one edge between any pair of vertex.

 

Output
For each test, print two lines.

The first line contains "YES" or "NO" for question 1. 

The second line contains "YES" or "NO" for question 2.
 
Sample Input
3 1 0 3 3 1 2 2 3 3 1 4 4 1 2 2 3 3 4 4 1
 
Sample Output
NO NO YES NO NO YES
Hint
If you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
 
Source
 
Recommend
hujie   |   We have carefully selected several similar problems for you:  6253 6252 6251 6250 6249 
大致题意:给定一个图,问是否存在奇环和偶环.
分析:是否有奇环非常简单,判断一下是不是二分图就可以了.对于偶环的话,题目给的是无向图,无向图上考虑环就先建出dfs树来,找返祖边,如果返祖点到目前点的深度差为奇数,那么环就是偶环,直接就判断完了.如果有多个奇环之间共边,那么就存在偶环.而奇环共边就构成了双连通分量,也就是说要先找到双连通分量,然后在每个双连通分量里找奇环,如果奇环的个数>1,那么就存在偶环.
          那么如何找双连通分量?把桥给找出来,桥是一定不在双连通分量里的,因为双连通分量里的任何一条边拿走,其中的点还是连通的,那么不是桥的边就属于双连通分量了.利用tarjan算法找桥.因为是无向图,还要多传递一个参数:父亲节点,并且返祖的时候还要看看终点与起点的深度差.对于每一个点,求出通向它的那条边是谁,反向边就可以通过^1来得到.这样一旦pre[u] = low[u],那么一开始通向u的边就是桥.
          无向图的tarjan算法要注意传递父亲节点这个信息.一个技巧:为了准确快速地获得通向当前点u的边在邻接表中的编号以及反向边的编号,可以将head初始化为-1,tot初始化为2.这样^1就是反向边了.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stack>
#include <algorithm>

using namespace std;

const int maxn = 600010;

int n, m, T, head[maxn], to[maxn], nextt[maxn], tot, id[maxn], pre[maxn], low[maxn], scc[maxn], scc_tot;
int ans1, ans2, dfs_clock, bridge[maxn], now[maxn], vis[maxn], deep[maxn], f[maxn], sum;
stack <int> s;

void init()
{
    memset(head, -1, sizeof(head));
    memset(id, 0, sizeof(id));
    memset(vis, 0, sizeof(vis));
    memset(now, 0, sizeof(now));
    memset(pre, 0, sizeof(pre));
    memset(low, 0, sizeof(low));
    memset(f, 0, sizeof(f));
    memset(deep, 0, sizeof(deep));
    memset(scc, 0, sizeof(scc));
    memset(bridge, 0, sizeof(bridge));
    sum = 0;
    scc_tot = 0;
    tot = 2;
    ans1 = ans2 = 0;
    dfs_clock = 0;
}

void add(int x, int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void tarjan(int u, int fa)
{
    pre[u] = low[u] = ++dfs_clock;
    s.push(u);
    for (int i = head[u]; i != -1; i = nextt[i])
    {
        int v = to[i];
        if (!pre[v])
        {
            id[v] = (i ^ 1);
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else
            if (v != fa && pre[v] < pre[u])
                low[u] = min(low[u], pre[v]);
    }
    if (pre[u] == low[u])
    {
        bridge[id[u]] = bridge[id[u] ^ 1] = 1;
        while (1)
        {
            int t = s.top();
            s.pop();
            if (t == u)
                break;
        }
    }
}

void dfs(int u, int depth,int fa)
{
    deep[u] = depth;
    vis[u] = now[u] = 1;
    for (int i = head[u]; i != -1; i = nextt[i])
    {
        if (bridge[i])
            continue;
        int v = to[i];
        if (!vis[v])
            dfs(v, depth + 1,u);
        else
            if (now[v] && v != fa)
            {
                int temp = depth - deep[v] + 1;
                if (temp % 2 == 1)
                {
                    ans1 = 1;
                    sum++;
                    if (sum > 1)
                        ans2 = 1;
                }
                else
                    ans2 = 1;
            }
    }
    now[u] = 0;
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        init();
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }
        for (int i = 1; i <= n; i++)
            if (!pre[i])
                tarjan(i, 0);
        for (int i = 1; i <= n; i++)
            if (!vis[i])
            {
                sum = 0;
                dfs(i, 1,0);
            }
        printf("%s\n", ans1 ? "YES" : "NO");
        printf("%s\n", ans2 ? "YES" : "NO");
    }

    return 0;
}

 

posted @ 2017-12-13 14:49  zbtrs  阅读(216)  评论(0编辑  收藏  举报