Euleriar Path 入门

一、前置技能

 >  图的概念

 >  dfs遍历图

 >  stack

 >  一笔画

二、定义

看过上面链接 是不是对一笔画产生了兴趣呢?

(A:没有!)

好吧……其实通俗来讲 欧拉路径就是OI意义下的一笔画

也就是 图中经过每条边一次并且仅一次的路径

欧拉回路就是满足欧拉路径性质的回路

同时我们定义欧拉图(其实就是一笔画出来的图)

存在欧拉回路的图称为欧拉图。
存在欧拉路径但不存在欧拉回路的图称为半欧拉图。

三、性质与定理

这种路径很特殊 不一定所有的图都有(比如大部分树)

规定一个点的度数为过这个点的边数(应该都知道)

刨去孤立点(没有度数的点)之后(显然,这样做并不会影响图中欧拉回路的存在性。)

  >  Q:先考虑无向图

发现我们考虑边无法推知下一步的方向 转而考虑点

然后就可以发现 在欧拉路径中除了起点和终点 进入每个点一次的时候一定会出去一次

所以除了起点和终点每个点的度数均为偶数

而欧拉回路中起点和终点重合

所以 欧拉图满足 每个点的度数为偶数

半欧拉图满足 仅有两个点的度数为奇数

那么 每个点度数为偶数的图(>0)一定有欧拉回路吗?

证明:

首先 如果图中没有回路 那么一定是一颗树 就一定有度数不是偶数的点(叶子)

所以一定有回路

然后比如我们找到了一个回路C

当我们把这条回路上的边都不计的时候

由于这是一条回路每一个点的度数减少量也一定是偶数(随手画个环看一下?)

剩下的图中就一定还有回路 把两个回路拼起来就有新的回路

最后全拼起来就能遍历所有的边 于是C就变成了欧拉回路

(欧拉路证明类似)

 >  Q:那么有向图?

同理 每条边有起点和终点 就把度数变成 入度出度 

当入度==出度 也就是进入的边数和出去的边数一样的时候 满足是欧拉图

仅有一个入度为1 仅有一个出度为1的时候 满足是半欧拉图

 > Q:那么混合图?

(啪!)

混合图欧拉回路是一个经典网络流问题 放别的地方讲

 >  Q:所以……怎么实现?

其实刚刚证明的时候就已经说完了最常用的 套圈法 的基本过程

实现的时候开一个栈存删掉的边(是否惰性删除都行)

最后沿着栈逆序输出就OK了

注意欧拉回路没有一定的起点 所以经常要输出字典序最小

这个时候邻接矩阵就比较方便 当然像某些dalao把链前排序也行

这里粘一下Code吧

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #define itn int
 6 #define ms(a,b) memset(a,b,sizeof a)
 7 #define rep(i,a,n) for(int i = a;i <= n;i++)
 8 #define per(i,n,a) for(int i = n;i >= a;i--)
 9 using namespace std;
10 typedef long long ll;
11 ll read() {
12     ll as = 0,fu = 1;
13     char c = getchar();
14     while(c < '0' || c > '9') {
15         if(c == '-') fu = -1;
16         c = getchar();
17     }
18     while(c >= '0' && c <= '9') {
19         as = as * 10 + c - '0';
20         c = getchar();
21     }
22     return as * fu;
23 }
24 const int N = 550;
25 //head
26 int n,m;
27 int a[N][N];
28 int stk[N<<1],top;
29 void dfs(int x) {
30     rep(y,1,n) {
31     if(!a[x][y]) continue;
32     a[x][y]--,a[y][x]--;
33     dfs(y);
34     }
35     stk[++top] = x;
36 }
37 int du[N];
38 int main() {
39     m = read();
40     rep(i,1,m) {
41     int x = read(),y = read();
42     n = max(max(x,y),n);
43     a[x][y]++,a[y][x]++;
44     du[x]++,du[y]++;
45     }
46     bool flag = 1;
47     rep(i,1,n) 
48     if(du[i] & 1) {
49         if(flag) dfs(i);
50         flag = 0;
51     }
52     if(flag) dfs(1);
53     while(top) printf("%d
",stk[top--]);
54     return 0;
55 }

应该是luogu一道绿题吧……

> 别忘了 总有人在等着你
原文地址:https://www.cnblogs.com/yuyanjiaB/p/9764348.html