图论----欧拉路径与欧拉回路

好博客:

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 }

 

posted @ 2022-10-26 21:19  次林梦叶  阅读(95)  评论(0)    收藏  举报