欧拉路源自歌德七桥问题,一个点出发到达另一个,走过每一条边,出发点和终点相同称为欧拉回路

判断欧拉路,如果所有点联通,且入出度相同,或者仅有两个出入度相差为一则有欧拉路

欧拉回路出入度必须相同才成立

 

有向图最小欧拉路的求法

 1 priority_queue<int>arr[N];
 2 int n, m;
 3 int in[N];
 4 int out[N];
 5 int ans[N];
 6 int l = 0;
 7 void dfs(int x) {
 8     while (!arr[x].empty()) {
 9         int x = -arr[x].top();
10         arr[x].pop();
11         dfs(x);
12         ans[++l] = x;
13     }
14 }
15 void euler() {
16     int x=0, y=0, z=0;
17     for (int i = 1; i <= n; ++i) {
18         if (in[i] != out[i])
19             z++;
20         if (in[i] == out[i] - 1)
21             y++,x=i;
22     }
23     if (!(!z || (y == 1 && z == 2))) {
24         cout << "No" << endl;
25         return;
26     }
27     if (!x) {
28         for (int i = 1; i <= n; ++i)
29         {
30             if (in[i])
31             {
32                 x = i;
33                 break;
34             }
35         }
36     }
37     dfs(x);
38     ans[++l] = x;
39     if (l != m + 1) {//判断所有的点是否联通
40         cout << "No" << endl;
41         return;
42     }
43     for (int i = l; i; --i) {
44         cout << ans[i] << ' ';
45     }
46 }
47 int main() {
48     cin >> n >> m;
49     for (int i = 0; i < m; ++i) {
50         int a, b;
51         cin >> a >> b;
52         arr[a].push(-b);//大根堆当小根堆用
53         out[a]++;
54         in[b]++;
55     }
56     euler();
57     return 0;
58 }

 

无相图,可使用矩阵去标记两方向的边,这里用高级的异或去标记反向边

 1 struct node {
 2     int i; int dex;//i表示去往的点,
 3     node(int i, int dex) {
 4         this->i = i;
 5         this->dex = dex;
 6     }
 7     bool operator<(const node& a)const {
 8         return this->i > a.i;
 9     }
10 };
11 priority_queue<node>arr[N];
12 int n, m;
13 int d[N];
14 int ans[N];
15 int l = 0;
16 int cnt = 1;
17 bool v[N];
18 void dfs(int x) {
19     while (!arr[x].empty()) {
20         int to = arr[x].top().i;
21         int bian = arr[x].top().dex;
22         arr[x].pop();
23         if (!v[bian]) {
24             v[bian] = v[bian ^ 1] = true;//反向边
25             ans[++l] = to;
26             dfs(to);
27         }
28     }
29 }
30 void euler() {
31     int x = 0, y = 0;
32     for (int i = n; i >= 1; --i) {//这里一定要从大到小,保证字典序最小
33         if (d[i] & 1) {
34             y++;
35             x = i;
36         }
37     }
38     if (y && y != 2) {
39         cout << "No" << endl;
40         return;
41     }
42     if (!x) {
43         for (int i = 1; i <= n; ++i)
44         {
45             if (d[i]) {
46                 x = i;
47                 break;
48             }
49         }
50     }
51     dfs(x);
52     ans[++l] = x;
53     if (l != m + 1) {
54         cout << "No" << endl;
55         return;
56     }
57     for (int i = l; i; --i)
58         cout << ans[i] << ' ';
59 }
60 int main() {
61     cin >> n >> m;
62     for (int i = 0; i < m; ++i) {
63         int a, b;
64         arr[b].push(node(a, ++cnt));
65         arr[a].push(node(b, ++cnt));
66         d[a]++;
67         d[b]++;
68     }
69     euler();
70     return 0;
71 }

 

二分图,一般通过染色法,只有无向图才能二分图

 1 int n, m;
 2 vector<int>arr[N];
 3 int v[N];
 4 bool dfs(int x) {
 5     for (int a : arr[x]) {
 6         if (!v[a]) {
 7             v[a] = 3 - v[x];
 8             if (!dfs(a))
 9                 return false;
10         }
11         else if (v[a] == v[x])
12             return false;
13     }
14     return true;
15 }
16 bool check() {
17     for (int i = 1; i <= n; ++i) {
18         if (!v[i]) {
19             v[i] = 1;
20             if (!dfs(i))
21                 return false;
22         }
23     }
24     return true;
25 }
26 int main() {
27     cin >> n >> m;
28     for (int i = 0; i < m; ++i) {
29         int a, b;
30         cin >> a >> b;
31         arr[a].push_back(b);
32         arr[b].push_back(a);
33     }
34     if (check())
35         cout << "YES" << endl;
36     else
37         cout << "NO" << endl;
38     return 0;
39 }