1. 程式人生 > >無向圖歐拉道路(歐拉回路)的判定與路徑打印

無向圖歐拉道路(歐拉回路)的判定與路徑打印

clu clas 檢查 names 連通圖 思路 return space 計算

歐拉道路描述的是無向圖的一個頂點出發的一條道路能夠經過每條邊恰好一次

歐拉回路指的是任意點出發都滿足上述性質

如果一個圖是歐拉道路或者歐拉回路,必須滿足兩個條件

第一個條件,這個圖是連通圖

第二個條件,所有點的度數滿足“一定的關系”

然後我們闡述一下“一定的關系”是什麽

檢查這個圖所有點的度數,求出這個圖度數給奇數的點的個數,我們也可以稱之為奇點數

如果沒有奇點,這個圖是一個歐拉回路,從任意點出發可以經過所有的邊並回到這個點

如果存在兩個奇點(這兩個奇點具有這樣的性質,這兩個點分別為起點和終點,其中起點的出度比入度大1,終點的入度比出度大1),那麽這個圖是一個歐拉道路

然後我們看一下程序怎麽寫,這裏只給出了求歐拉回路的程序

思路是這樣的,先判連通,然後計算點的度數,如果有奇點就肯定不是歐拉回路了(有可能是歐拉道路)

int n,m;
int G[maxn][maxn],a[maxn],vis[maxn],vi[maxn][maxn];

n個點m條邊

G鄰接矩陣,a是統計每一個點度數的,vis是判連通時用到的數組,而vi是打印歐拉路徑的時候的判重數組

void dfs(int u)
{
    for(int i=1;i<=n;i++)
    if(G[u][i]&&!vis[i]){vis[i]=1;dfs(i);}
}

判連通,超熱血的DFS

void euler(int u)  //
如果不是歐拉回路,參數必須傳道路起點 { for(int v=1;v<=n;v++) if(G[u][v]&&!vi[u][v]){vi[u][v]=vi[v][u]=1;euler(v);printf("%d %d\n",u,v);} //有向圖中去掉vi[v][u],真正路徑把printf壓棧 }

打印歐拉路徑的函數,也十分熱血

下面給出完整實現,這個程序是判斷歐拉回路的一定要註意

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4
const int maxn=1005; 5 int n,m; 6 int G[maxn][maxn],a[maxn],vis[maxn],vi[maxn][maxn]; 7 void dfs(int u) 8 { 9 for(int i=1;i<=n;i++) 10 if(G[u][i]&&!vis[i]){vis[i]=1;dfs(i);} 11 } 12 void euler(int u) //如果不是歐拉回路,參數必須傳道路起點 13 { 14 for(int v=1;v<=n;v++) 15 if(G[u][v]&&!vi[u][v]){vi[u][v]=vi[v][u]=1;euler(v);printf("%d %d\n",u,v);} 16 //有向圖中去掉vi[v][u],真正路徑把printf壓棧 17 } 18 int main() 19 { 20 while(cin>>n) 21 { 22 memset(G,0,sizeof(G)); 23 memset(a,0,sizeof(a)); 24 memset(vis,0,sizeof(vis)); 25 if(n==0) break; 26 cin>>m; 27 for(int i=1;i<=m;i++){int x,y;cin>>x>>y;G[x][y]=1;G[y][x]=1;} 28 bool flag=1;int tmp=0; 29 vis[1]=1;dfs(1); 30 for(int i=1;i<=n;i++) 31 if(vis[i]==0) flag=0; 32 if(flag) 33 { 34 for(int i=1;i<=n;i++) 35 for(int j=1;j<=n;j++) 36 if(G[i][j]) a[i]++; 37 for(int i=1;i<=n;i++) 38 if(a[i]%2!=0) tmp++; 39 } 40 if(flag&&tmp==0) cout<<1<<endl; 41 else cout<<0<<endl; 42 } 43 return 0; 44 }

如果一個問題可以轉換成求歐拉道路或者歐拉回路的形式,那答案就顯然了

無向圖歐拉道路(歐拉回路)的判定與路徑打印