歐拉圖的斷定歐拉路的求法

其中 dfs 的代碼 主要來自: https://blog.csdn.net/Jaster_wisdom/article/details/51067234算法

 

一,前言dom

這裏講的都是無向圖,沒講有向的。ide

其中,若是 無向圖沒有奇數度結點,則具備歐拉回路,是歐拉圖測試

           若是 無向圖有兩個奇數度結點,則僅有歐拉通路,是半歐拉圖spa

           此外,則該無向圖既不是歐拉圖也不是半歐拉圖.net

測試數據的圖:code

 

 

 

二,Fleury 算法blog

1, 算法思想get

選取起點,其中歐拉圖的起點任意,半歐拉圖的起點從 兩個奇度結點中的任意一個 開始。string

而後從起點依次選邊,每選一條邊就從圖中刪去。選取條件是:① 與上一條已選取的邊關聯;② 除非無別的邊可 選,不然不能選割邊(橋)。

 

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

 

 

 

=========== ========= ======== ======= ====== ===== ==== === == =

哪裏會有人喜歡孤獨,只是不喜歡失望罷了。

                 —— 村上春樹

相關文章
相關標籤/搜索