zoukankan      html  css  js  c++  java
  • 欧拉回路

    题目描述

        欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?

    输入描述:

        测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是节点数N ( 1 < N < 1000 )和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。当N为0时输入结束。

    输出描述:

        每个测试用例的输出占一行,若欧拉回路存在则输出1,否则输出0。
    示例1

    输入

    3 3
    1 2
    1 3
    2 3
    3 2
    1 2
    2 3
    0
    

    输出

    1
    0

    题目链接:欧拉回路

    参考资料:链接

    最终AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int MAX=1005;
    int cnt[MAX], father[MAX];
    int findFather(int x){
        if(x != father[x]) father[x] = findFather(father[x]);
        return father[x];
    }
    int main(){
        int i, u, v, t, N, M;
        set<int> si; //记录出现的且非孤立的结点
        set<int>::iterator it;
        while(cin >> N >> M){
            for(i=0; i<N; i++){
                cnt[i] = 0;
                father[i] = i;
            }
            si.clear();
            for(i=0; i<M; i++){
                scanf("%d %d", &u, &v);
                if(u == v) continue;
                si.insert(u);
                si.insert(v);
                cnt[u]++; //入度+1
                cnt[v]++;
                u = findFather(u); //找父节点
                v = findFather(v);
                if(u != v) father[v] = u;
            }
            t = 0; //0 表示存在欧拉回路
            for(it=si.begin(); it!=si.end(); it++){
                if(cnt[*it] & 1){
                    t = 1; //表示不存在欧拉回路
                    break;
                }
            }
            if(t){ //说明存在度数为奇数的点
                printf("0
    ");
                continue;
            }
            t = 0; //统计集合的个数
            for(it=si.begin(); it!=si.end(); it++) if(*it == father[*it]) t++;
            if(t == 1) printf("1
    ");
            else printf("0
    ");
        }
        return 0;
    }

    总结:题干虽然简洁,但是要解出这个题,还必须深刻理解题干,即:欧拉回路的要求是有且仅有一次经过所有边。这也就是说,要么图中出现的点都是孤立的点,要么出现的所有边只可以构成一个回路(存在多个回路还不行)。

    刚开始想采用图中的遍历方式解决,后来写到一半写不下去,因为越写思路越复杂~然后参考了别人的思路,过了几天再自己写出来,我用的方法是:并查集+统计结点度数;具体思路过程如下:

    1、如果结点u == v,或者在输入的边中没有出现某个结点,那么这样的点都可以视为孤立结点;
    
    2、否则,用set(去重)记录出现的边所连接的两个结点值。并且,此时还要统计结点的度数,以及归并这两个集合。
    
    3、输入完数据后,可以从条件“是否存在度数为奇数的结点”和“是否有且只存在一个集合(即一个回路)”判断。
    
    4、这两个条件都必须检查,只有不存在度数为奇数的结点且只存在一个集合,才输出1;否则,输出0。

    回看上述过程,这题看起来有点难的原因无非两个:一、是否可以将问题描述转化为用并查集+统计结点度数的方法,并得到对应的判断标准;二、是否可以想到用set来存储度数非0的结点(即排除孤立结点)。

    如果可以把这两个问题想透彻,那么这个题就简单很多了。最后啰嗦几句,从最近刷的题来看,很多对于自己有难度的题都是难在这种问题的转化上。比如,遇到图的问题,可能最有效的解决方式并不是用图的相关算法,反而可能是采用并查集或结合其它算法才能解决。如果自己直接局限在图的算法中不能自拔,那么就可能很难顺利将题目解决了。

  • 相关阅读:
    PHP数组、函数
    PHP 基本内容
    Swift基础--tableview练习
    iOS 协议delegate分六步
    UI09_UITableView 使用 单例
    css清除浮动float的三种方法总结,为什么清浮动?浮动会有那些影响?一起来$('.float')
    CSS 如何使DIV层水平居中
    HTML转义字符大全
    jQuery选择器总结
    jQuery 学习笔记_01
  • 原文地址:https://www.cnblogs.com/heyour/p/12759405.html
Copyright © 2011-2022 走看看