1.定義
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; }
