hihocder 1181 : 欧拉路·二
因?yàn)橄噙B的兩個(gè)數(shù)字總是相同的,不妨我們只寫一次,那么這個(gè)例子可以寫成:3-2-4-3-5-1。6個(gè)數(shù)字剛好有5個(gè)間隙,每個(gè)間隙兩邊的數(shù)字由恰好對(duì)應(yīng)了一塊骨牌。
如果我們將每一個(gè)數(shù)字看作一個(gè)點(diǎn),每一塊骨牌看作一條邊。你覺得是怎么樣的呢?
小Ho:以這個(gè)例子來(lái)說(shuō)的話,就是:
要把所有的骨牌連起來(lái),也就是把所有的邊都走一次。咦,這不是歐拉路問(wèn)題么!
小Hi:沒錯(cuò),這問(wèn)題其實(shí)就是一個(gè)歐拉路的問(wèn)題,不過(guò)和上一次不一樣的在于,這一次我們要找出一條歐拉路徑。
小Ho:那我們應(yīng)該如何來(lái)找一條路徑呢?
小Hi:我們還是借用一下上次的例子吧
使用我們上一次證明歐拉路判定的方法,我們?cè)谶@個(gè)例子中找到了2條路徑:
L1: 4-5-2-3-6-5 L2: 2-4-1-2假設(shè)我們棧S,記錄我們每一次查找路徑時(shí)的結(jié)點(diǎn)順序。當(dāng)我們找到L1時(shí),棧S內(nèi)的情況為:
S: 4 5 2 3 6 5 [Top]此時(shí)我們一步一步出棧并將這些邊刪除。當(dāng)我們到節(jié)點(diǎn)2時(shí),我們發(fā)現(xiàn)節(jié)點(diǎn)2剛好是L1與L2的公共節(jié)點(diǎn)。并且L2滿足走過(guò)其他邊之后回到了節(jié)點(diǎn)2。如果我們?cè)谶@個(gè)地方將L2先走一遍,再繼續(xù)走L1不就剛好走過(guò)了所有邊么。
而且在上一次的證明中我們知道,除了L1之外,其他的路徑L2、L3...一定都滿足起點(diǎn)與終點(diǎn)為同一個(gè)點(diǎn)。所以從任意一個(gè)公共節(jié)點(diǎn)出發(fā)一定有一條路徑回到這個(gè)節(jié)點(diǎn)。
由此我們得到了一個(gè)算法:
在原圖中找一個(gè)L1路徑
從L1的終點(diǎn)往回回溯,依次將每個(gè)點(diǎn)出棧。并檢查當(dāng)前點(diǎn)是否還有其他沒有經(jīng)過(guò)的邊。若存在則以當(dāng)前點(diǎn)為起點(diǎn),查找L2,并對(duì)L2的節(jié)點(diǎn)同樣用棧記錄重復(fù)該算法。
當(dāng)L1中的點(diǎn)全部出棧后,算法結(jié)束。
在這里我們?cè)賮?lái)一個(gè)有3層的例子:
在這個(gè)例子中:
L1: 1-2-6-5-1 L2: 2-3-7-2 L3: 3-4-8-3第一步時(shí)我們將L1壓入棧S,同時(shí)我們用一個(gè)數(shù)組Path來(lái)記錄我們出棧的順序:
S: [1 2 6 5 1] Path:然后出棧到節(jié)點(diǎn)2時(shí)我們發(fā)現(xiàn)了2有其他路徑,于是我們把2的另一條路徑加入:
S: 1 [2 3 7 2] Path: 1 5 6此時(shí)L2已經(jīng)走完,然后再開始彈出元素,直到我們發(fā)現(xiàn)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此時(shí)的Path就正好是我們需要的歐拉路徑。
小Ho:原來(lái)這樣就能求出歐拉路,真是挺巧妙的。
小Hi:而且這個(gè)算法在實(shí)現(xiàn)時(shí)也有很巧妙的方法。因?yàn)镈FS本身就是一個(gè)入棧出棧的過(guò)程,所以我們直接利用DFS的性質(zhì)來(lái)實(shí)現(xiàn)棧,其偽代碼如下:
DFS(u):While (u存在未被刪除的邊e(u,v))刪除邊e(u,v)DFS(v)EndPathSize ← PathSize + 1Path[ PathSize ] ← u
要注意,在DFS的時(shí)候,如果歐拉圖當(dāng)中存在奇數(shù)度的頂點(diǎn),那么一定要從該頂點(diǎn)出發(fā),如果沒有,則任一點(diǎn)都行。。。。
#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; }總結(jié)
以上是生活随笔為你收集整理的hihocder 1181 : 欧拉路·二的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: phonegap免费视频
- 下一篇: new与malloc的区别,以及内存分配