一,前言
這裏講的都是無向圖,沒講有向的。
其中,如果 無向圖沒有奇數度結點,則具有歐拉回路,是歐拉圖
如果 無向圖有兩個奇數度結點,則僅有歐拉通路,是半歐拉圖
此外,則該無向圖既不是歐拉圖也不是半歐拉圖
測試數據的圖:
二,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
*/
View Code
三,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
*/
View Code
=========== ========= ======== ======= ====== ===== ==== === == =
哪裏會有人喜歡孤獨,只是不喜歡失望罷了。
—— 村上春樹