前往
大廳
主題

LeetCode - 1192. Critical Connections in a Network 解題心得

Not In My Back Yard | 2021-06-06 00:00:06 | 巴幣 2 | 人氣 319

題目連結:


題目意譯:
現在有著 n 個伺服器編號為 0 ~ n - 1 並以無向的「伺服器到伺服器」之連結 connections 所連接在一起,形成一個網路。其中 connections[i] = [ai, bi] ,代表著伺服器 ai 到伺服器 bi 的一個連接。任何伺服器都可以直接地或是間接地經由網路到達其他伺服器。

一個關鍵連接為一個連接,其滿足如果將其移除會使得某些伺服器無法到達其他某些伺服器。

以任意順序回傳網路中全部的關鍵連接。

限制:
2 ≦ n ≦ 10 ^ 5
n - 1 ≦ connections.length ≦ 10 ^ 5
0 ≦ ai 、 bi ≦ n - 1
ai ≠ bi
不會有重複的連接。



範例測資:
輸入: n = 4, connections = [[0,1],[1,2],[2,0],[1,3]]
輸出: [[1,3]]
解釋: [[3,1]] 也可以被接受。


解題思維:
有一個著名的演算法叫做 Tarjan 演算法(Robert Tarjan 所發明,參見維基頁面)。

我們不以純文字敘述陳述演算法,直接利用範例說明:
現在有一個無向圖,如下



我們從任意節點開始。在這裡,我們從最左邊的節點開始
當我們每探訪一個節點時,我們為每個節點附加一個數對 (V, L)。其中 V 代表我們在什麼時間點探訪到這個節點的(也就是時間戳記)、L 則等下才會予以說明。



掃過節點 0 的相鄰節點,而我們看到了節點 1。節點 1 還沒被探訪過,所以我們探訪它



接著再掃過節點 1 的相鄰節點。我們先忽略節點 0 和節點 4(這邊只是為了說明順序之方便),先看節點 2 。節點 2 還沒被探訪過,所以我們探訪它



掃過節點 2 的相鄰節點。同樣為了方便先忽略節點 1。節點 3 還沒被探訪,所以



掃過節點 3 的相鄰節點。此時,節點 1 和節點 2 都已被探訪了(因為那兩個節點已經有了數對 (2, 2) 和 (3, 3))。我們先看節點 2 ,節點 2 是前一刻在的節點(也就是前一個節點),所以我們將其忽略。

但是節點 1 不一樣,節點 1 不是前一個節點。而且根據其時間戳 V = 2 ,而當前節點(節點 3)的時間戳為 V = 4 ,所以代表此時我們繞回了節點 1。

所以節點 1 — 節點 2 — 節點 3 這三個節點形成一個強連通元件(Strongly Connected Component,SCC),在這邊剛好是一個環。不過本題不是要找 SCC。

因為繞回了節點 1 ,所以我們將節點 3 數對中的 L 更新為 2,代表其所在的 SCC 之最低探訪時間戳(L 代表為 Lowest),如下



因為節點 3 沒有其他相鄰節點了,所以我們回到節點 2 。將節點 2 的 L 值也改為 2 (因為節點 3 的 L 之更動),如下



因為節點 2 沒有其他相鄰節點了,所以我們回到節點 1 。節點 1 的 L 不需更動,因為節點 1 的 L ≦ 節點 2 的 L,如下



接著因為節點 4 沒有被探訪過,所以我們探訪它



節點 4 除了節點 1(前一個節點)以外沒有其他相鄰節點,所以我們回到節點 1



然後此時我們發現節點 1 的時間戳 V 小於節點 4 的最低時間戳 L,代表兩者處於不同的 SCC。

也就代表著節點 1 到節點 4 的那條邊,即是一條關鍵邊(Critical Edge,又稱 Bridge)同時也是本題的關鍵連接。圖中的關鍵連接以綠色邊表示



再來,因為節點 1 沒有其他相鄰節點了(記住,節點 0 是它的前一個節點),所以我們回到節點 0



此時再度發現節點 0 的時間戳 V 小於節點 1 的最低時間戳 L,代表節點 0 到節點 1 的邊為關鍵邊,如下



最後因為節點 0 沒有其他相鄰節點了,所以整個圖完成了探訪。因此我們得到如下圖所示
的兩條綠色邊——即關鍵連接 [0,1] 和 [1,4] 。



因此,我們可以看到對於每個節點 X,看它的所有相鄰節點(記得忽略前一個節點)。對於每個相鄰節點 Y,先判斷它有無探訪過。有的話,則將 X 的 L 更新為 min(X 的 L, Y 的 V) ,其代表我們從 Y 經由某個路徑到達了 X 然後又回到了 Y 。

如果 Y 沒有探訪過就探訪看看。當從 Y 回到 X 時,我們將 X 的 L 更新為 min(X 的 L, Y 的 L) ,代表說如果 Y 處於一個 SCC ,則 X 有可能也是位於同一個 SCC。然後再判斷 X 的 V 是否小於 Y 的 L。

如果是則代表我們沒辦法藉由其他路徑從 X 跑到 Y。因此 X 與 Y 的那一條邊即是關鍵邊(關鍵連接)。

以上就是 Tarjan 演算法在找關鍵邊時的過程。其實還不夠完整,因為本題的圖之種類不會出現重邊、自環等等特殊情況。如果有這些特殊情況,則上面的判斷需要做一些微調(但是大致相同)。

其時間複雜度是根據儲存圖的邊之資料結構而定。假設圖的節點數為 V 個(注意,請不要跟上面說明中的 V 搞混)、邊數為 E 個。則如果儲存邊的資料結構為
鄰接矩陣(Adjacency Matrix)
O(V ^ 2)
因為每個節點掃過其相鄰節點時要看過所有其他節點並根據矩陣內容來得知兩者有無邊連接。

鄰接表(Adjacency List)則為
O(V + E)
因為每個節點可以直接地得知其相鄰節點(不像上面的鄰接矩陣)。

鄰接矩陣與鄰接表的定義可以參見這題




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

Kilink
這台完全沒IDEA去解 好難
2022-05-18 09:24:22

更多創作