尤拉路和尤拉迴路

2021-07-04 11:21:55 字數 4036 閱讀 2289

尤拉環:圖中經過每條邊一次且僅一次的環;

尤拉路徑:圖中經過每條邊一次且僅一次的路徑;

尤拉圖:有至少乙個尤拉環的圖;

半尤拉圖:沒有尤拉環,但有至少一條尤拉路徑的圖。

【無向圖】

乙個無向圖是尤拉圖當且僅當該圖是連通的(注意,不考慮圖中度為0的點,因為它們的存在對於圖中是否存在尤拉環、尤拉路徑沒有影響)且所有點的度數都是偶數;乙個無向圖是半尤拉圖當且僅當該圖是連通的且有且只有2個點的度數是奇數(此時這兩個點只能作為尤拉路徑的起點和終點);

證明:因為任意乙個點,尤拉環(或尤拉路徑)從它這裡進去多少次就要出來多少次,故(進去的次數+出來的次數)為偶數,又因為(進去的次數+出來的次數)=該點的度數(根據定義),所以該點的度數為偶數。

【有向圖】

乙個有向圖是尤拉圖當且僅當該圖的基圖(將所有有向邊變為無向邊後形成的無向圖,這裡同樣不考慮度數為0的點)是連通的且所有點的入度等於出度;乙個有向圖是半尤拉圖當且僅當該圖的基圖是連通的且有且只有乙個點的入度比出度少1(作為尤拉路徑的起點),有且只有乙個點的入度比出度多1(作為終點),其餘點的入度等於出度。

證明:與無向圖證明類似,乙個點進去多少次就要出來多少次。

【無向圖、有向圖中尤拉環的求法】

與二分圖匹配演算法類似,是乙個深度優先遍歷的過程,時間複雜度o(m)(因為一條邊最多被訪問一次)。核心**(邊是用邊表儲存的而不是鄰接鍊錶,因為無向圖中需要對其逆向的邊進行處理,在有向圖中,可以用鄰接鍊錶儲存邊):

[cpp]view plain

copy

void

dfs(

intx)  

}  可以參考

傳說中的套圈法。

演算法思想的樸素表達

對於尤拉圖,從乙個節點出發,隨便往下走(走過之後需要標記一下,下次就不要來了),必然也在這個節點終止(因為除了起始節點,其他節點的度數都是偶數,只要能進去就能出來)。這樣就構成了乙個圈,但因為是隨便走的,所以可能會有些邊還沒走過就回來了。我們就從終止節點逆著往前查詢,直到找到第乙個分叉路口,然後從這個節點出發繼續上面的步驟,肯定也是可以找到一條回到這個點的路徑的,這時我們把兩個圈連在一起。當你把所有的圈都找出來後,整個尤拉迴路的尋找就完成了。

尋找尤拉迴路時,起始節點是可以任意選擇的。如果是有基度頂點要尋找尤拉通路,則從基度頂點出發就好了,上述步驟依然有效。

演算法思想的書面表達

乙個解決此類問題基本的想法是從某個節點開始,然後查出乙個從這個點出發回到這個點的環路徑。現在,環已經建立,這種方法保證每個點都被遍歷.如果有某個 點的邊沒有被遍歷就讓這個點為起點,這條邊為起始邊,把它和當前的環銜接上。這樣直至所有的邊都被遍歷。這樣,整個圖就被連線到一起了。 

更正式的說,要找出尤拉路徑,就要迴圈地找出出發點。按以下步驟: 

任取乙個起點,開始下面的步驟 

如果該點沒有相連的點,就將該點加進路徑中然後返回。 

如果該點有相連的點,就列一張相連點的表然後遍歷它們直到該點沒有相連的點。(遍歷乙個點,刪除乙個點) 

處理當前的點,刪除和這個點相連的邊, 在它相鄰的點上重複上面的步驟,把當前這個點加入路徑中. 

下面是偽**: 

# circuit is a global array 

find_euler_circuit 

circuitpos = 0 

find_circuit(node 1) 

# nextnode and visited is a local array 

# the path will be found in reverse order 

find_circuit(node i) 

if node i has no neighbors then 

circuit(circuitpos) = node i 

circuitpos = circuitpos + 1 

else 

while (node i has neighbors) 

pick a random neighbor node j of node i 

delete_edges (node j, node i) 

find_circuit (node j) 

circuit(circuitpos) = node i 

circuitpos = circuitpos + 1 

要找尤拉路徑, 只要簡單的找出乙個度為奇數的節點,然後呼叫 find_circuit 就可以了.

一點點**(pku 2337裡面截過來的,具體請看

[cpp]view plain

copy

//主函式中呼叫下面這個函式

euler(start, -1); //因為直接從start出發,所以第二個引數用-1代替,輸出的時候要忽略掉。

//euler函式就是用的傳說中的套圈法,是乙個迭代的過程

//npath是乙個全域性變數,記錄已經找到的邊的數量

//邊儲存在adj中,是用陣列實現的鍊錶結構(就跟很多hash那樣,首節點的資料域不用,只有指標部分有效)

void

euler(

intcur, 

intedgen) 

//cur當前到達的節點 edgen上一被選擇的邊,即上乙個節點通過edgen到達的cur

path[npath++] = edgen; //後序記錄,如果要保持搜尋時候邊的優先順序,則逆向輸出

}  

要注意的是在res中寫入是逆序的,所以初始的v應設成(邊數-1)。

但是有乙個問題是,這是遞迴實現的,當點數過多時有爆棧危險,所以最好使用非遞迴:

[cpp]view plain

copy

void

dfs()  

if(!ff)   

}  }  

中國郵遞員問題問題(管梅谷,1960):一位郵遞員從郵局出發投遞郵件,經過他所管轄的每條街道至少一次,然後回到郵局。請為他選擇一條路線,使其所行路程盡可能短。圖論模型:求賦權連通圖中含所有邊的權最小的閉途徑。這樣的閉途徑稱為最優郵路。

思路:(1)若g是euler圖,則g的euler閉跡便是最優郵路,可用fleury演算法求得;(2)若g不是euler圖,則含有所有邊的閉途徑必須重複經過一些邊,最優郵路要求重複經過的邊的權之和達到最小。閉途徑重複經過一些邊,實質上可看成給圖g新增了一些重複邊(其權與原邊的權相等),最終消除了奇度頂點形成乙個euler圖。因此,在這種情況下求最優郵路可分為兩步進行:首先給圖g新增一些重複邊得到乙個euler圖g*,使得新增邊的權之和最小;然後用fleury演算法求g*的一條euler閉跡。這樣便得到g的最優郵路。問題是:如何給圖g新增重複邊得到euler圖g*,使得新增邊的權之和最小?

edmonds-johnson方法的基本思想:先求出g中所有2k個奇度頂點間的最短路。為了從中選出k條權最小且無公共端點的最短路,以g的所有奇度點為頂點構造賦權完全圖k2k,兩頂點連邊上的權為這兩個奇度點在g中最短路的權。求賦權完全圖k2k的最小權完美匹配,該完美匹配的k條邊對應的k對頂點間的最短路必定無公共邊(否則,若兩條路有公共邊,則刪去公共邊後可得到兩條連線奇度頂點的更短路,從而對應出權更小的完美匹配,矛盾)。沿這k條最短路新增重複邊,便可得到最優郵路euler圖g*。然後找出g*的euler閉跡,即得到最優郵路。

edmonds-johnson演算法:step1. 若g中無奇度頂點,令g*=g,轉step2;否則轉step3。step2. 求g*中的euler閉跡,結束。step3. 求g中所有奇度頂點對之間的最短路。step4. 以g中奇度頂點集為頂點集,構作賦權完全圖k2k,其中各邊的權為對應兩頂點在g中最短路的權。step5. 求k2k中最小權完美匹配m。step6. m中每條邊所匹配的兩點在g中都對應有一條最短路,在g中沿這些最短路新增重複邊,得euler圖g*,轉step2。

尤拉路和尤拉迴路

尤拉路 尤拉路是指從圖中任意乙個點開始到圖中任意乙個點結束的路徑,並且圖中每條邊通過的且只通過一次。1.無向連通圖存在尤拉路的條件 所有點度都是偶數,或者恰好有兩個點度是奇數,則有尤拉路。若有奇數點度,則奇數點度點一定是尤拉路的起點和終點,否則可取任意一點作為起點。2.有向連通圖存在尤拉路的條件 滿...

尤拉迴路,尤拉路

參考以上 判斷尤拉路,尤拉迴路 注意圖聯通,可以dfs 或者並查集 一 無向圖 尤拉迴路 每個頂點度數都是偶數 尤拉路 所有點度數為偶數,或者只有2 個點度數為奇數 二 有向圖 非混合 尤拉迴路 每個頂點入度等於出度 尤拉路 每個頂點入度等於出度 或者只有1 個點入度比出度小 1,從這點出發,只有 ...

尤拉路 尤拉迴路

1 尤拉路 在乙個連通圖中存在一條路,經過途中所有邊一次且僅一次,這條路叫做尤拉路。2 尤拉迴路 在乙個連通圖中存在一條路,經過途中所有邊一次且僅一次,出發點亦是終點,這樣的路是尤拉迴路。1 無向圖有一條尤拉路 圖是連通的,且全部的結點的度是偶數 就是尤拉迴路的情況 或只有兩個結點的度是奇數。2 無...