dfs求欧拉道路

从一个节点出发的一条路径每条边只经过一次,则把这条路称作欧拉道路。

欧拉道路存在着这样的性质除起点和终点以外所有经过的节点的出度和入度相等,也就是说除起点和终点以外的节点的度都为偶数。

同时一个无向图是连通的,且最多存在两个奇点,则一定存在欧拉道路,并且如果是有两个奇点,欧拉道路一定是从一个奇点出发到达另外一个奇点,如果没有奇点,则从任何一个节点出发然后最终回到该点(欧拉回路),奇点为一的情况是不存在的。

对于存在欧拉道路的情况,最多只能有两个点的入度不等于出度,而且必须是其中一个节点的入度比出度大一,而另一个节点相反入度比出度少一,相差的这个一也就分别作起点和终点。前提是有向图忽略方向后图是连通图。

概括的说:

判断是否存在欧拉道路的方法是:忽略方向后图连通并且奇点数量为0或者2.

判断是否存在欧拉回路的方法是:忽略方向后图连通并且奇点数量为0。

判断图连通与否可以通过dfs从一个节点出发遍历整个忽略方向后的图,并且统计节点数量,若dfs统计出的节点数量和总的节点数量不同则说明图不连通。还有一种方法是并查集。

获取欧拉道路的算法:(一个图完全可能存在多条欧拉道路,这里的只求一条):

[cpp] view plain copy

  1. struct edge{
  2. int begin,end;
  3. edge(int a=0,int b=0):begin(a),end(b){}
  4. };
  5. int N;                 //总的节点数量
  6. bool flag[MaxN][MaxN]; //标记两个节点间是否直接连通
  7. bool vis[MaxN][MaxN];  //标记连接两个节点的边是否被访问过
  8. stack<edge> ans;       //存放路径中的各条边
  9. //同时适用于欧拉道路和回路
  10. //初次调用参数应该为起点坐标
  11. void euler(int here){
  12. for(int i=0;i<N;i++){
  13. if(flag[here][i]&&!vis[here][i]){
  14. vis[here][i]=vis[i][here]=true;
  15. euler(i);
  16. ans.push(edge(here,i));
  17. }
  18. }
  19. }

关于为什么统计边的信息要放在递归之后?既然能一笔画完为什么不直接打印?看下面的图。

图只有两个奇点1和10,也就是说存在一条欧拉道路,但图中存在一条桥边2-7,若在访问3456节点之前就去访问了7节点,则按照dfs打印出来的欧拉路径为1-2-7-10-9-8-7-12-11-10-4-3-6-5,但10和4之间并没有直接连通,也就是说虽然任然访问了全部边但顺序出错。

其实上面这个错的顺序是由1-2-7-10-9-8-7-12-11-10和一条欧拉回路4-3-6-5这两部分组成的,因为奇点最多为2并且必须要分别作为起点和终点的性质,类似1-2-7-10-9-8-7-12-11-10这样的欧拉路径在欧拉图中最多存在一条(也就是有桥的情况下),删除掉这条路径上的全部边之后剩下的只能是欧拉回路或者为空,访问有可能一次就直接访问完了全部边,但也有可能先访问桥边,造成结果错误。

利用函数入栈先进后出的性质,若先访问了桥,因为欧拉回路有从任何一点出发最终一定回到起点的性质,如果先访问桥边最后就会剩下一些欧拉回路,如果最后访问桥边就不会剩下欧拉回路,先访问完欧拉回路再访问桥边能访问到最多的节点,利用栈倒序就是为了达到类似效果。

原文地址:https://www.cnblogs.com/TAMING/p/8538896.html

时间: 2024-10-08 03:17:57

dfs求欧拉道路的相关文章

无向图欧拉道路(欧拉回路)的判定与路径打印

欧拉道路描述的是无向图的一个顶点出发的一条道路能够经过每条边恰好一次 欧拉回路指的是任意点出发都满足上述性质 如果一个图是欧拉道路或者欧拉回路,必须满足两个条件 第一个条件,这个图是连通图 第二个条件,所有点的度数满足"一定的关系" 然后我们阐述一下"一定的关系"是什么 检查这个图所有点的度数,求出这个图度数给奇数的点的个数,我们也可以称之为奇点数 如果没有奇点,这个图是一个欧拉回路,从任意点出发可以经过所有的边并回到这个点 如果存在两个奇点(这两个奇点具有这样的性

UVA 10129 Play on Words(欧拉道路)

题意:给你n个字符串,问你是否可以出现一条链,保证链中每个字符串的第一个元素与上一个字符串的最后一个元素相同,注意可能重复出现同一个字符串 题解:以每一个字符串第一个元素指向最后一个元素形成一个有向图,判断这个有向图是否可以形成欧拉路就好 注意可能有重边与自环,因此求欧拉路时判断的是是否使用完了所有的边,求起点时注意出度与入度的计算 欧拉道路是从一个点一笔画完整张图(欧拉回路保证回到起点),注意除了起点与终点以外所有的点出度入度相等 起点出度大入度1,终点相反(所有的点出入度相等也可以),根据这

UVA 10441 - Catenyms(欧拉道路)

UVA 10441 - Catenyms 题目链接 题意:给定一些单词,求拼接起来,字典序最小的,注意这里的字典序为一个个单词比过去,并非一个个字母 思路:欧拉回路.利用并查集判联通,然后欧拉道路判定,最后dfs输出路径 代码: #include <cstdio> #include <cstring> #include <string> #include <vector> #include <iostream> #include <algo

POJ 2513 Colored Sticks(欧拉道路+字典树+并查集)

http://poj.org/problem?id=2513 题意: 给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的. 思路: 题目很明显的是欧拉道路的问题. 欧拉道路的关键是: ①图是连通的. ②最多只能有两个奇点.(不能只存在一个奇点) 本来是想用map映射的,但是太多了,比较费时,这里用字典树的话会比较省时,判断图是否连通可以用并查集来完成. 1 #include<iostream> 2 #include<algori

Nyoj42 一笔画问题 (欧拉道路)

http://acm.nyist.net/JudgeOnline/problem.php?pid=42题目链接 #include <cstdio> #include <cstring> #define CLR(arr) memset(arr,0,sizeof(arr)) #define P 1001 int G[P],fa[P]; int find(int x){return x==fa[x]?x:x=find(fa[x]);} int main() {     int n,a,b

UVa 10129 Play On Words【欧拉道路 并查集 】

题意:给出n个单词,问这n个单词能否首尾接龙,即能否构成欧拉道路 按照紫书上的思路:用并查集来做,取每一个单词的第一个字母,和最后一个字母进行并查集的操作 但这道题目是欧拉道路(下面摘自http://blog.csdn.net/hcbbt/article/details/9316301) 关于欧拉道路(from Titanium大神): 判断有向图是否有欧拉路 1.判断有向图的基图(即有向图转化为无向图)连通性,用简单的DFS即可.如果图都不连通,一定不存在欧拉路 2.在条件1的基础上   对于

UVA-10129 Play on Words (判断欧拉道路的存在性)

题目大意:给出一系列单词,当某个单词的首字母和前一个单词的尾字母相同,则这两个单词能链接起来.给出一系列单词,问是否能够连起来. 题目分析:以单词的首尾字母为点,单词为边建立有向图,便是判断图中是否存在欧拉道路.有向图中存在欧拉路径的两个条件是:1.忽略边的方向性后,底图联通:2.奇点个数为0时.奇点个数为2并且满足起点的入度比出度小1和终点的出度比入度大1时,欧拉道路一定存在: 判断图的连通性有两种方法:1.利用并查集,只判断有几个根节点即可:2.使用DFS,做法实质上就是判断联通块的个数:

HDU 4850 Wow! Such String!(欧拉道路)

HDU 4850 Wow! Such String! 题目链接 题意:求50W内的字符串,要求长度大于等于4的子串,只出现一次 思路:需要推理,考虑4个字母的字符串,一共有26^4种,这些由这些字符串,如果一个字符串末尾加上一个字符,可以变成另一个字符串的话,就当作这有一条边,每多一个字符多一个结点,那么对于这道题目,一共就能有26^4 + 3条边,在加上尾巴可以多放3个,一共是26^4+3个边,这些边全部连起来就是要的字符串,这样就可以知道每个节点会经过的次数为26,这样就只要考虑如何把这些节

【UVa】12118 Inspector&#39;s Dilemma(欧拉道路)

题目 题目 ? ? 分析 很巧秒的一道题目,对着绿书瞎yy一会. 联一下必须要走的几条边,然后会形成几个联通分量,统计里面度数为奇数的点,最后再减去2再除以2.这样不断相加的和加上e再乘以t就是答案, 为什么呢?题目要求最短距离,那么必定是欧拉道路,那么为了构造出最短欧拉道路,要将奇度数的点减小至2个,然而各个道路不一定联通,还需要计算一下联通块数量n,结果加上n-1后,再乘t,因为需要n-1条边将各个联通块连接起来. 注意题目已保证每两个点都有路,所以上面才能那么肆无忌惮的连边. ? ? 代码