Hierholzer算法&重新安排行程

1、Hierholzer算法

歐拉跡是指一條包含圖中所有邊的一條路徑,該路徑中所有的邊會且僅會出現一次。

一個無向圖中包含歐拉跡,當且僅當下面兩條性質同時滿足:

  • 圖是連通的
  • 圖中每個頂點的度均爲偶數

而一個有向圖包含歐拉跡,當且僅當下面兩條性質同時滿足:

  • 圖是連通的
  • 圖中每個頂點入度和出度相同

Hierholzer算法用於在連通圖尋找歐拉跡,其流程非常簡單。

從一個可能的起點出發,進行深度優先搜索,但是每次沿着輔助邊從某個頂點移動到另外一個頂點的時候,都需要刪除這個輔助邊。如果沒有可移動的路徑,則將所在結點加入到棧中,並返回。

void dfs(Node node, Deque trace){
	while(!node.edges.isEmpty())
	{
		Node next = node.edges.removeLast();
		dfs(next, trace);
	}
	trace.addLast(node);
}

最後得到的棧中保存的就是整個歐拉跡中的頂點。

這個算法應用起來非常簡單,下面我們先證明幾條性質。

性質1. 如果圖中包含閉歐拉跡,則棧的底部存儲的必定是起點。如果圖中包含的是開歐拉軌跡,則棧底部存儲的是與起點不同的另外一個奇度數端點。

證明:當我們要入棧時,說明當前所在頂點沒有任何邊了。考慮到從起點出發到當前結點的路徑中,除了起點和當前頂點外,所有的頂點都失去了偶數度數(在移除了途經的邊後)。如果起點和當前頂點不同,那麼兩者都失去了奇數度數。如果圖中包含閉歐拉跡,這意味着所有頂點的初始度數都是偶數,而當前頂點的剩餘度數爲0,表示當前頂點的初始度數必定是奇數,當然這是不可能的,因此假設不成立,當前頂點就是起點。同樣的對於開歐拉跡,當前頂點不可能是起點,否則起點的度數就是偶數,而開歐拉跡中起點和終點的度數一定是奇數。這樣就能推出當前頂點既不是起點度數也是偶數,因此一定是終點。

性質2.如果圖中包含閉歐拉跡,入棧的倒數第二個頂點一定是路徑中的第二個頂點。

證明:由於路徑中的第二個頂點入棧,說明起點已經入棧過,換言之,起點已經沒有多餘的邊了。

參考原文:https://taodaling.github.io/blog/2019/04/25/Hierholzer%E7%AE%97%E6%B3%95/

2、例題:重新安排行程

給定一個機票的字符串二維數組 [from, to],子數組中的兩個成員分別表示飛機出發和降落的機場地點,對該行程進行重新規劃排序。所有這些機票都屬於一個從JFK(肯尼迪國際機場)出發的先生,所以該行程必須從 JFK 出發。

說明:

如果存在多種有效的行程,你可以按字符自然排序返回最小的行程組合。例如,行程 ["JFK", "LGA"] 與 ["JFK", "LGB"] 相比就更小,排序更靠前
所有的機場都用三個大寫字母表示(機場代碼)。
假定所有機票至少存在一種合理的行程。
示例 1:

輸入: [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
輸出: ["JFK", "MUC", "LHR", "SFO", "SJC"]
示例 2:

輸入: [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
輸出: ["JFK","ATL","JFK","SFO","ATL","SFO"]
解釋: 另一種有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"]。但是它自然排序更大更靠後。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/reconstruct-itinerary/

套用歐拉跡的公式,可以這樣理解:

def findItinerary(self, tickets):
        import collections
        maps = collections.defaultdict(list)
        for start, end in sorted(tickets)[::-1]:
            maps[start].append(end)
            
        def dfs(cur, maps, res):
            while maps[cur]:
                dfs(maps[cur].pop(), maps, res)
            res.append(cur)
            return res[::-1]

        return dfs("JFK", maps, [])

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章