其中 dfs 的代碼 主要來自: https://blog.csdn.net/Jaster_wisdom/article/details/51067234
一,前言
這里講的都是無向圖,沒講有向的。
其中,如果 無向圖沒有奇數度結點,則具有歐拉回路,是歐拉圖
如果 無向圖有兩個奇數度結點,則僅有歐拉通路,是半歐拉圖
此外,則該無向圖既不是歐拉圖也不是半歐拉圖
測試數據的圖:
二,Fleury 算法
1, 算法思想
選取起點,其中歐拉圖的起點任意,半歐拉圖的起點從 兩個奇度結點中的任意一個 開始。
然后從起點依次選邊,每選一條邊就從圖中刪去。選取條件是:① 與上一條已選取的邊關聯;② 除非無別的邊可 選,否則不能選割邊(橋)。
2,步驟
① 判斷該圖是什么圖
② 選擇起點
③ 刪邊
④ 將刪除的邊 加入 歐拉路中
⑤ 循環 ③ ④,直至 無邊 可刪
3,代碼

#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> #define N 1000 int a[N][N]; //鄰接矩陣 int n, m; // n 點數 , m 邊數 int judge_bridge(int i) // 通過判斷以 i 為終點的邊 是否 只有一個,來判斷這條邊是否是 割邊 { int cnt = 0; for (int j = 0; j < n; j++) { if (a[i][j]) cnt++; } if (cnt == 1) return 0; return 1; } void Fleury(int cur) // cur 為起點 { int t = 0; // 記錄割邊的終點 int f3 = 0; // 標記 第一條邊 while (1) { int f1 = 0; // 標記 是否有找到 正常邊 int f2 = 0; // 如果有 割邊,記錄 第一條割邊 for (int j = 0; j < n; j++) { if (a[cur][j]) { if (judge_bridge(j)) // 如果這條邊不是割邊,則刪除這條邊 { f1 = 1; a[cur][j] = 0; a[j][cur] = 0; printf(f3 == 0 ? "(%d,%d)" : "->(%d,%d)", cur, j); f3 = 1; cur = j; break; } if (judge_bridge(j) == 0 && f2 == 0) // 記錄可能出現的割邊,以備不時之需 { f2++; t = j; } } } if (f1 == 0 && f2 == 1) // 到了不選割邊不行的地步了 { a[cur][t] = 0; a[t][cur] = 0; printf(f3 == 0 ? "(%d,%d)" : "->(%d,%d)", cur, t); f3 = 1; cur = t; } if (f1 == 0 && f2 == 0) // 無邊可選,鄰接矩陣空了,算法結束 { puts(""); break; } } } void creat() // 直接 輸入鄰接矩陣 { for (int i = 0; i < n; i++)//使用鄰接矩陣表示圖 { for (int j = 0; j < n; j++) { scanf("%d", &a[i][j]); } } } void judge() { int odd = 0; // 存奇數度數 的個數 int flag = 0; // 存 奇度邊 的編號,如果是 半歐拉圖 就從 奇度邊 出發,若是 歐拉回路,就隨便從 0 開始 for (int i = 0; i < n; i++) { int cnt = 0; for (int j = 0; j < n; j++) // 統計每個結點的 度數 cnt += a[i][j]; if (cnt % 2) // 若為 奇數,總數 +1 { flag = i; odd++; } } if (odd == 0) { printf("判定:該無向圖沒有奇數度結點,具有歐拉回路,是歐拉圖\n"); printf("歐拉回路為:"); Fleury(flag); } else if (odd == 2) { printf("判定:該無向圖有兩個奇數度結點,僅有歐拉通路,是半歐拉圖\n"); printf("歐拉通路為:"); Fleury(flag); } else printf("判定:該無向圖既不是歐拉圖也不是半歐拉圖\n"); } int main(void) { while (scanf("%d", &n) != EOF) // 輸入結點數 嘗試了一下就 234 會有 歐拉路 { memset(a, 0, sizeof(a)); creat(); // 直接 輸入鄰接矩陣 judge(); // 判斷 該 鄰接矩陣 是什么圖,若有歐拉路 則輸出 路徑 } system("pause"); return 0; } /* 測試數據1:歐拉回路 7 0 1 0 0 1 0 0 1 0 1 1 1 0 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 1 0 測試數據2:歐拉通路 5 0 1 1 0 0 1 0 1 1 1 1 1 0 1 1 0 1 1 0 1 0 1 1 1 0 */
三,DFS
1,個人感覺,不知對錯
① 這里面雖然沒有判斷割邊,但是判斷了孤立點,它用深搜進行刪邊,這里的深搜只進行搜索刪邊,並沒有回溯。
但是它將結點壓入棧中了,然后再通過 棧中的結點 進行回溯,將孤立點加入通路中。那沒什么存下來的路徑不是散亂的點呢?
② 我們要明白一個前提就是這是個 歐拉圖 或者是 半歐拉圖,如果是從起點開始搜索的話,是有可能一次搜完的。
那什么時候會出現幾條路徑呢,只有它在有其他的路可選的情況下,搜索了割邊。
③ 我猜測如果搜索的是割邊的話,那么剩余圖一定是回路(因為畫了好幾次都是這樣,也不會證明,不知道對不對 ┌(; ̄◇ ̄)┘)
所以在我們通過 棧 里面的 結點 進行回溯時,在中間對剩余圖進行再次深搜,就相當於在原通路中插入一條回路,仍然還是一條通路。
這樣才能存下來的路徑不是散亂的點
2,代碼

#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> #include<stack> using namespace std; #define N 1000 int map[N][N], way[N]; stack<int>s; int n, m; // 點數 邊數 void dfs(int k) { s.push(k); for (int i = 0; i < n; i++) // 一條路 刪到沒路 不管有無割邊 { if (map[k][i]) { map[i][k] = map[k][i] = 0; dfs(i); break; } } } void Fleury(int k) { stack<int>ss; s = ss; // 棧的清空 int cnt = 0; s.push(k); // 起點入棧 while (s.size()) { int vertex = s.top(); s.pop(); int flag = 0; for (int i = 0; i < n; i++) // 通過判斷 與vertx 相鄰的邊的個數 來判斷是否 這點是否 是孤立點 { if (map[vertex][i] > 0) // 只要有邊 就可以刪 { flag = 1; break; } } if (flag == 0) // 該點是 孤立點 way[cnt++] = vertex; else // 不是孤立點 可以繼續 刪邊 dfs(vertex); } for (int i = cnt - 1; i > 0; i--) // 打印路徑 printf("%d->", way[i]); printf("%d\n", way[0]); } void judge() { int odd = 0; // 存奇數度數 的個數 int flag = 0; // 存 奇度邊 的編號,如果是 半歐拉圖 就從 奇度邊 出發,若是 歐拉回路,就隨便從 0 開始 for (int i = 0; i < n; i++) { int cnt = 0; for (int j = 0; j < n; j++) // 統計每個結點的 度數 cnt += map[i][j]; if (cnt % 2) // 若為 奇數,總數 +1 { flag = i; odd++; } } if (odd == 0) { printf("判定:該無向圖沒有奇數度結點,具有歐拉回路,是歐拉圖\n"); printf("歐拉回路為:"); Fleury(flag); } else if (odd == 2) { printf("判定:該無向圖有兩個奇數度結點,僅有歐拉通路,是半歐拉圖\n"); printf("歐拉通路為:"); Fleury(flag); } else printf("判定:該無向圖既不是歐拉圖也不是半歐拉圖\n"); } int main(void) { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int x, y; scanf("%d%d", &x, &y); map[x][y] = map[y][x] = 1; } judge(); system("pause"); return 0; } /* 測試數據1:歐拉回路 7 10 0 1 0 4 1 2 1 4 1 3 2 3 3 4 4 5 5 6 6 3 測試數據2:歐拉通路 5 8 0 1 0 2 1 2 1 3 1 4 2 3 2 4 3 4 */
=========== ========= ======== ======= ====== ===== ==== === == =
哪里會有人喜歡孤獨,只是不喜歡失望罷了。
—— 村上春樹