好博客:
https://www.acwing.com/solution/content/53434/
https://ycw123.blog.luogu.org/ou-la-hui-lu-yu-ou-la-lu-jing
《介绍与性质》
对于无向图来说:
如果不是欧拉回路:
起点的度是奇数(度是出度+入度),因为我们从起点出发,如果以后还到达了起点,必然是进入起点,
然后离开起点(因为我这里的前提是:不是欧拉回路,是欧拉路径)。所以度是奇数
同理,终点的度也是奇数
其余的中间点度都是偶数
如果是欧拉回路:
从起点出发,到起点结束,全部节点的度都是偶数
对于有向图来说:
如果不是欧拉回路:
起点的出度=起点的入度+1,终点的入度=终点的出度+1
其余点出度==入度
如果是欧拉回路:
全部点:出度==入度
《关于建立图上的注意点》
在判断是否可以建成欧拉回路或欧拉路径的过程中我们会用上cd[].rd[],表示一个点的出度与入度
在无向图的建立过程中,我一般习惯如下:
这个时候我其实把无向图建立成了上面右边的情况
但是其实当边a->b用过后,b->a边也应该判断为用过
这个时候我判读是否可以有欧拉回路的条件是:
像这个图也可以建成欧拉回路,所以不能单独只通过bool vis,这种来判断边是否被看过,特别是在无向图的建边过程中
因为有多个自环与重边在欧拉路径中是被允许的
《一些问题》
如何记录欧拉路径?
如何在使用vector建边时删去边?
原题:https://www.acwing.com/problem/content/1186/
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <vector> 5 #include <map> 6 #include <stack> 7 using namespace std; 8 const int N = 1e5 + 5; 9 int t, n, m, rd[N], cd[N]; 10 struct node 11 { 12 int to, w; 13 }; 14 //在使用结构体map的时候一定要用operator重载一下,否则会报错 15 struct Node 16 { 17 int from, to, w; 18 bool operator<(const Node &a) const 19 { 20 if (a.from == from) 21 { 22 if (a.to == to) 23 return a.w < w; 24 else 25 return a.to < to; 26 } 27 else 28 return a.from < from; 29 } 30 }; 31 stack<int> ans; 32 vector<node> sides[N]; 33 map<Node, bool> vis; 34 //用来模拟删除边的数组,pos[i]表示在sides[i]中下次要看的边是 35 // sides[i][pos[i]],0~pos[i]-1的边都已经看过; 36 int pos[N]; 37 38 void dfs(int x) 39 { 40 //这里后面更新是i=max(i+1,pos[x]),而不是i=pos[x] 41 //是因为可能里面的if语句进不去,防止导致死循环 42 for (int i = pos[x]; i < sides[x].size(); i = max(i + 1, pos[x])) 43 { 44 int to = sides[x][i].to, w = sides[x][i].w; 45 if (!vis[{x, to, w}]) 46 { 47 vis[{x, to, w}] = true; 48 if (t == 1) 49 vis[{to, x, -w}] = true; 50 pos[x] = i + 1; 51 dfs(sides[x][i].to); 52 //这是加入边的写法 53 ans.push(w); 54 } 55 //这个加入点的写法 56 // ans.push(x); 57 } 58 } 59 int main() 60 { 61 cin >> t >> n >> m; 62 for (int i = 1; i <= m; i++) 63 { 64 int a, b; 65 scanf("%d%d", &a, &b); 66 sides[a].push_back({b, i}); 67 cd[a]++, rd[b]++; 68 69 //表示是无向图时:1 70 if (t == 1) 71 { 72 sides[b].push_back({a, -i}); 73 rd[a]++, cd[b]++; 74 } 75 } 76 77 bool flag = true; 78 for (int i = 1; i <= n; i++) 79 if ((t == 1 && cd[i] % 2) || (t != 1 && cd[i] != rd[i])) 80 { 81 flag = false; 82 break; 83 } 84 if (flag) 85 { 86 for (int i = 1; i <= n; i++) 87 if (sides[i].size() != 0) 88 { 89 dfs(i); 90 break; 91 } 92 93 if (ans.size() != m) 94 cout << "NO" << endl; 95 else 96 { 97 cout << "YES" << endl; 98 while (ans.size()) 99 { 100 cout << ans.top() << " "; 101 ans.pop(); 102 } 103 cout << endl; 104 } 105 } 106 else 107 cout << "NO" << endl; 108 return 0; 109 }
无向图模板:
原题链接:https://www.luogu.com.cn/problem/P2731
这里用times[a][b]来记录边a->b的条数,上面不这么用是因为上面的点数太大,开二维会爆,所以以后能开二维就开二维吧,比较容易
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <map> 5 #include <vector> 6 #include <stack> 7 using namespace std; 8 9 typedef pair<int, int> PII; 10 const int N = 510; 11 vector<int> sides[N]; 12 int times[N][N]; 13 14 int m, cd[N], rd[N]; 15 stack<int> ans; 16 17 int pos[N]; 18 void dfs(int x) 19 { 20 for (int i = pos[x]; i < sides[x].size(); i = max(i + 1, pos[x])) 21 { 22 int to = sides[x][i]; 23 if (times[x][to] > 0) 24 { 25 times[x][to]--, times[to][x]--; 26 pos[x] = i + 1; 27 dfs(to); 28 } 29 } 30 ans.push(x); 31 } 32 33 int main() 34 { 35 cin >> m; 36 int mind = 520, maxd = -520; 37 for (int i = 1; i <= m; i++) 38 { 39 int a, b; 40 scanf("%d%d", &a, &b); 41 mind = min(mind, min(a, b)); 42 maxd = max(maxd, max(a, b)); 43 sides[a].push_back(b); 44 sides[b].push_back(a); 45 cd[a]++, rd[b]++; 46 cd[b]++, rd[a]++; 47 times[a][b]++, times[b][a]++; 48 } 49 int start = -1; 50 for (int i = mind; i <= maxd; i++) 51 { 52 if (sides[i].size() != 0 && start == -1) 53 start = i; 54 if (sides[i].size() != 0 && cd[i] % 2) 55 { 56 start = i; 57 break; 58 } 59 } 60 for (int i = mind; i <= maxd; i++) 61 sort(sides[i].begin(), sides[i].end()); 62 63 dfs(start); 64 65 while (ans.size()) 66 { 67 cout << ans.top() << endl; 68 ans.pop(); 69 } 70 71 return 0; 72 }
标签:图论,int,pos,----,回路,include,sides,欧拉 From: https://www.cnblogs.com/cilinmengye/p/16830040.html