hihocder 1181 : 欧拉路·二
因為相連的兩個數字總是相同的,不妨我們只寫一次,那么這個例子可以寫成:3-2-4-3-5-1。6個數字剛好有5個間隙,每個間隙兩邊的數字由恰好對應了一塊骨牌。
如果我們將每一個數字看作一個點,每一塊骨牌看作一條邊。你覺得是怎么樣的呢?
小Ho:以這個例子來說的話,就是:
要把所有的骨牌連起來,也就是把所有的邊都走一次。咦,這不是歐拉路問題么!
小Hi:沒錯,這問題其實就是一個歐拉路的問題,不過和上一次不一樣的在于,這一次我們要找出一條歐拉路徑。
小Ho:那我們應該如何來找一條路徑呢?
小Hi:我們還是借用一下上次的例子吧
使用我們上一次證明歐拉路判定的方法,我們在這個例子中找到了2條路徑:
L1: 4-5-2-3-6-5 L2: 2-4-1-2假設我們棧S,記錄我們每一次查找路徑時的結點順序。當我們找到L1時,棧S內的情況為:
S: 4 5 2 3 6 5 [Top]此時我們一步一步出棧并將這些邊刪除。當我們到節點2時,我們發現節點2剛好是L1與L2的公共節點。并且L2滿足走過其他邊之后回到了節點2。如果我們在這個地方將L2先走一遍,再繼續走L1不就剛好走過了所有邊么。
而且在上一次的證明中我們知道,除了L1之外,其他的路徑L2、L3...一定都滿足起點與終點為同一個點。所以從任意一個公共節點出發一定有一條路徑回到這個節點。
由此我們得到了一個算法:
在原圖中找一個L1路徑
從L1的終點往回回溯,依次將每個點出棧。并檢查當前點是否還有其他沒有經過的邊。若存在則以當前點為起點,查找L2,并對L2的節點同樣用棧記錄重復該算法。
當L1中的點全部出棧后,算法結束。
在這里我們再來一個有3層的例子:
在這個例子中:
L1: 1-2-6-5-1 L2: 2-3-7-2 L3: 3-4-8-3第一步時我們將L1壓入棧S,同時我們用一個數組Path來記錄我們出棧的順序:
S: [1 2 6 5 1] Path:然后出棧到節點2時我們發現了2有其他路徑,于是我們把2的另一條路徑加入:
S: 1 [2 3 7 2] Path: 1 5 6此時L2已經走完,然后再開始彈出元素,直到我們發現3有其他路徑,同樣壓入棧:
S: 1 2 [3 4 8 3] Path: 1 5 6 2 7之后依次彈出剩下的元素:
S: Path: 1 5 6 2 7 3 8 4 3 2 1此時的Path就正好是我們需要的歐拉路徑。
小Ho:原來這樣就能求出歐拉路,真是挺巧妙的。
小Hi:而且這個算法在實現時也有很巧妙的方法。因為DFS本身就是一個入棧出棧的過程,所以我們直接利用DFS的性質來實現棧,其偽代碼如下:
DFS(u):While (u存在未被刪除的邊e(u,v))刪除邊e(u,v)DFS(v)EndPathSize ← PathSize + 1Path[ PathSize ] ← u
要注意,在DFS的時候,如果歐拉圖當中存在奇數度的頂點,那么一定要從該頂點出發,如果沒有,則任一點都行。。。。
#include<iostream> #include<cstdio> #include<cstring> using namespace std;int n,m,edge[1001][1001],degree[1001]; int path[1001],len;void dfs(int u) {for(int i = 1; i <= n; i++){if(edge[u][i] > 0){edge[u][i]--, edge[i][u]--;dfs(i);}}path[len++] = u; }int main() { while(scanf("%d%d",&n,&m)!=EOF){int u,v;memset(edge,0,sizeof(edge));memset(degree,0,sizeof(degree));for(int i = 1; i <= m; i++){scanf("%d%d",&u,&v);edge[u][v]++, edge[v][u]++;degree[u]++, degree[v]++;}int k = 1;for(int i = 1; i <= n; i++){if(degree[i] % 2 == 1){k = i;break;}}len = 0;dfs(k);for(int i = len-1; i >= 0; i--)printf("%d ",path[i]);printf("\n");}return 0; }總結
以上是生活随笔為你收集整理的hihocder 1181 : 欧拉路·二的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: phonegap免费视频
- 下一篇: new与malloc的区别,以及内存分配