zoukankan      html  css  js  c++  java
  • nyist 42 一笔画 (欧拉回路 + 并查集)

    nyoj42

    分析:

    若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。

    若该路径是一个圈,则称为欧拉(Euler)回路。 具有欧拉回路的图称为欧拉图(简称E图)。具有欧拉路径但不具有欧拉回路的图称为半欧拉图。

    先说一下欧拉路径、欧拉回路的充要条件:

    1.无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数);

    2.无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点;

    3.有向连通图D是欧拉图,当且仅当该图为连通图且D中每个结点的入度=出度

    4.有向连通图D含有欧拉通路,当且仅当该图为连通图且D中除两个结点外,其余每个结点的入度=出度,且此两点满足deg-(u)-deg+(v)=±1。(起始点s的入度=出度-1,结束点t的出度=入度-1 或两个点的入度=出度)

    5.一个非平凡连通图是欧拉图当且仅当它的每条边属于奇数个环。

    而我们这道题一笔画, 正是要经过图中的每条边一次。 也就是说我们判断一下所个图是否存在欧拉路径就可以啦。

    首先求图是否连通(判断连通我们用并查集就好啦, 简单、易懂),

    再判断图是否存在欧拉路径(所有点度数为偶数或者只有两个点度数为奇数,其它均为偶数)。

    还有注意输出的是 Yes / No

    #include<iostream>
    #include<cstdio>
    #include<string.h>
    #include<cstring>
    #include<vector>
    using namespace std;
    
    int t, n, m, sum, pre[1010], du[1010], v[1010][1010];
    int find(int x)
    {
        int i, j, r;
        i = x; r = x;
        while(r != pre[r])
            r = pre[r];
        while(pre[i] != r)
        {
            j = pre[i];
            pre[i] = r;
            i = j;
        }
        return pre[x];
    }
    int main()
    {
        cin >> t;
        while(t--)
        {
            scanf("%d%d", &n, &m);
            memset(v, 0, sizeof(v));
            memset(du, 0, sizeof(du));
            for(int i = 1; i <= n; i++) pre[i] = i;
            for(int i = 1; i <= m; i++)
            {
                int x, y;
                scanf("%d%d", &x, &y);
                int fx = find(x);
                int fy = find(y);
                if(fx != fy)
                    pre[fx] = fy;
                if(v[x][y] == 0)
                {
                    v[x][y] = 1;
                    v[y][x] = 1;
                    du[x]++;//记录度数
                    du[y]++;
                }
            }
            int ans = find(1);
            int flag = 1;
            for(int i = 2; i <= n; i++)// 判断是否是连通图
            {
                int fx = find(i);
                if(fx != ans)  
                {
                    flag = 0;
                    break;
                }
            }
            sum = 0;
            if(flag == 1)
            {
                for(int i = 1; i <= n; i++)// 若是连通图, 再判断节点度数为奇数共有几个
                {
                    if(du[i] % 2 == 1)
                        sum++;
                }
                if(sum == 0 || sum == 2)
                    printf("Yes
    ");
                else
                    printf("No
    ");
            }
            else
                printf("No
    ");
        }
        return 0;
    }
  • 相关阅读:
    【BZOJ4566】[HAOI2016]找相同字符
    【BZOJ3238】[AHOI2013]差异
    【BZOJ4698】[SDOI2008]Sandy的卡片
    后缀数组(SA)总结
    【HDU3117】Fibonacci Numbers
    线性常系数齐次递推总结
    【HDU4565】So Easy!
    【BZOJ3144】[HNOI2013]切糕
    【BZOJ1070】[SCOI2007]修车
    【LOJ6433】【PKUSC2018】最大前缀和
  • 原文地址:https://www.cnblogs.com/wd-one/p/4539336.html
Copyright © 2011-2022 走看看