歐拉回路基本概念+判斷+求解


1.定義

如果圖G(有向圖或者無向圖)中所有邊一次僅且一次行遍所有頂點的通路稱作歐拉通路。
如果圖G中所有邊一次僅且一次行遍所有頂點的回路稱作歐拉回路。
具有歐拉回路的圖稱為歐拉圖(簡稱E圖)。具有歐拉通路但不具有歐拉回路的圖稱為半歐拉圖。

2. 定理及推論

歐拉通路和歐拉回路的判定是很簡單的,請看下面的定理及推論。

無向圖G存在歐拉通路的充要條件是:

G為連通圖,並且G僅有兩個奇度結點(度數為奇數的頂點)或者無奇度結點。

推論1:

1) 當G是僅有兩個奇度結點的連通圖時,G的歐拉通路必以此兩個結點為端點。
2) 當G是無奇度結點的連通圖時,G必有歐拉回路。
3) G為歐拉圖(存在歐拉回路)的充分必要條件是G為無奇度結點的連通圖。

 

有向圖D存在歐拉通路的充要條件是:

D為有向圖,D的基圖連通,並且所有頂點的出度與入度都相等;或者除兩個頂點外,其余頂點的出度與入度都相等,而這兩個頂點中一個頂點的出度與入度之差為1,另一個頂點的出度與入度之差為-1。

推論2:
1) 當D除出、入度之差為1,-1的兩個頂點之外,其余頂點的出度與入度都相等時,D的有向歐拉通路必以出、入度之差為1的頂點作為始點,以出、入度之差為-1的頂點作為終點。
2) 當D的所有頂點的出、入度都相等時,D中存在有向歐拉回路。
3) 有向圖D為有向歐拉圖的充分必要條件是D的基圖為連通圖,並且所有頂點的出、入度都相等。

 

3.歐拉通路回路存在的判斷

根據定理和推論,我們可以很好的找到歐拉通路回路的判斷方法,定理和推論是來自離散數學的內容,這里就給出簡明的判斷方法:

A.判斷歐拉通路是否存在的方法

有向圖:圖連通,有一個頂點出度大入度1,有一個頂點入度大出度1,其余都是出度=入度。

無向圖:圖連通,只有兩個頂點是奇數度,其余都是偶數度的。

B.判斷歐拉回路是否存在的方法

有向圖:圖連通,所有的頂點出度=入度。

無向圖:圖連通,所有頂點都是偶數度。

4.歐拉回路的應用

A.哥尼斯堡七橋問題

B.一筆畫問題

C.旋轉鼓輪的設計

 

5.歐拉回路的求解

A.  DFS搜索求解歐拉回路

基本思路:利用歐拉定理判斷出一個圖存在歐拉回路或歐拉通路后,選擇一個正確的起始頂點,用DFS算法遍歷所有的邊(每一條邊只遍歷一次),遇到走不通就回退。在搜索前進方向上將遍歷過的邊按順序記錄下來。這組邊的排列就組成了一條歐拉通路或回路。

#include<cstdio>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define MAX 2010
using namespace std;
int maps[MAX][MAX];
int in[MAX];
int t[MAX];
int flag;
int k;
int Max,Min;
int DFS(int x)
{
    int i;
    for(i=Min;i<=Max;i++)
    {
        if(maps[x][i])///從任意一個與它相連的點出發
        {
            maps[x][i]--;///刪去遍歷完的邊
            maps[i][x]--;
            DFS(i);
        }
    }
    t[++k]=x;///記錄路徑,因為是遞歸所有倒着記
}
int main()
{
    int n,i,x,y;
    Max=-9999;
    Min=9999;
    flag=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        maps[x][y]++;
        maps[y][x]++;
        Max=max(x,max(y,Max));
        Min=min(x,min(y,Min));
        in[x]++;
        in[y]++;
    }
    for(i=Min;i<=Max;i++)
    {
        if(in[i]%2)///存在奇度點,說明是歐拉通路
        {
            flag=1;
            DFS(i);
            break;
        }
    }
    if(!flag)///全為偶度點,從標號最小的開始找
    {
        DFS(Min);
    }
    for(i=k;i>=1;i--)
    {
        printf("%d\n",t[i]);
    }
    return 0;
}

 

B.  Fleury(佛羅萊)算法

Fleury算法是對DFS爆搜的一種改進,使用DFS漫不經心的隨意走是效率不高的,Fleury是一種有效的算法。

關鍵是能不走橋就不去走橋,實在無路可走了才去走橋!!!

 

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int ans[200];
int top;
int N,M;
int mp[200][200];
void dfs(int x)
{
    int i;
    top++;
    ans[top]=x;
    for (i=1; i<=N; i++)
    {
        if(mp[x][i]>0)
        {
            mp[x][i]=mp[i][x]=0;///刪除此邊
            dfs(i);
            break;
        }
    }
}

void fleury(int x)
{
    int brige,i;
    top=1;
    ans[top]=x;///將起點放入Euler路徑中
    while(top>=0)
    {
        brige=0;
        for (i=1; i<=N; i++) /// 試圖搜索一條邊不是割邊(橋)
        {
            if(mp[ans[top]][i]>0)///存在一條可以擴展的邊
            {
                brige=1;
                break;
            }
        }
        if (!brige)/// 如果沒有點可以擴展,輸出並出棧
        {
            printf("%d ", ans[top]);
            top--;
        }
        else     /// 否則繼續搜索歐拉路徑
        {
            top--;///為了回溯
            dfs(ans[top+1]);
        }
    }
}

int main()
{
    int x,y,deg,num,start,i,j;
    scanf("%d%d",&N,&M);
    memset(mp,0,sizeof (mp));
    for(i=1;i<=M; i++)
    {
        scanf("%d%d",&x,&y);
        mp[x][y]=1;
        mp[y][x]=1;
    }
    num=0;
    start=1;///這里初始化為1
    for(i=1; i<=N; i++)
    {
        deg=0;
        for(j=1; j<=N; j++)
        {
            deg+=mp[i][j];
        }
        if(deg%2==1)///奇度頂點
        {
            start=i;
            num++;
        }
    }
    if(num==0||num==2)
    {
        fleury(start);
    }
    else
    {
        puts("No Euler path");
    }
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM