zoukankan      html  css  js  c++  java
  • 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
    ", ans1 ? "YES" : "NO");
            printf("%s
    ", ans2 ? "YES" : "NO");
        }
    
        return 0;
    }
  • 相关阅读:
    前端错误监控上报公共方法,可在父页面及iframe子页面同时使用
    python3.7爬取墨菲定律保存在本地txt
    实现一个左滑删除功能
    用docsify快速构建文档,并用GitHub Pages展示
    最常用的快捷键总结
    有价值的帖子或博客链接
    解决8080端口占用问题
    用gulp构建你的前端项目
    移动端右侧栏导航面板
    自己封装一个弹框插件
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8032826.html
Copyright © 2011-2022 走看看