欧拉回路

题目描述

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

输入描述:

    测试输入包含若干测试用例。每个测试用例的第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\n");
            continue;
        }
        t = 0; //统计集合的个数
        for(it=si.begin(); it!=si.end(); it++) if(*it == father[*it]) t++;
        if(t == 1) printf("1\n");
        else printf("0\n");
    }
    return 0;
}

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

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

1、如果结点u == v,或者在输入的边中没有出现某个结点,那么这样的点都可以视为孤立结点;

2、否则,用set(去重)记录出现的边所连接的两个结点值。并且,此时还要统计结点的度数,以及归并这两个集合。

3、输入完数据后,可以从条件“是否存在度数为奇数的结点”和“是否有且只存在一个集合(即一个回路)”判断。

4、这两个条件都必须检查,只有不存在度数为奇数的结点且只存在一个集合,才输出1;否则,输出0。

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

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

posted @ 2020-04-23 11:13  已是夕阳,不如放下  阅读(328)  评论(0编辑  收藏  举报