1. 程式人生 > >有向圖的匯點 -- 兼 ACM PKU POJ 2186 ( Popular Cows ) 解題報告

有向圖的匯點 -- 兼 ACM PKU POJ 2186 ( Popular Cows ) 解題報告

題意:奶牛的夢想是成為牛群中最受歡迎的奶牛,即受其它所有牛的歡迎。“歡迎”是具有傳遞性,即如果牛A認為牛B受歡迎,牛B覺得牛C受歡迎,則牛A也隱含地認為牛C受歡迎。現在,給一組點對 (A,B) 表示 A 認為 B 受歡迎,找出有多少最受歡迎的奶牛。

這是一個有向圖上的問題。用圖上的頂點表示奶牛,有向邊 (A,B) 表示 A 變為 B 受歡迎,則最受歡迎的牛是那些能被其它頂點所到達的頂點。最暴力的解法是,對每一個頂點,判斷是否能夠為其它所有的頂點所到達。這個演算法的複雜度是 O(V2E),其中,V 為頂點數量,E 為有向邊的數量。對於題目的資料規模,顯然會超時。

實際上,存在 O(V+E) 的演算法。這需要我們仔細研究和分析有向圖的一些性質。

事實一:如果圖上有至少兩個頂點的出度為 0,則沒有頂點是最受歡迎的,即答案為 0。

顯然,如果這個有向圖上有環,則環上的奶牛意見一致,即若 C 能被環上的某點所到達,也必然能被環上的其它任意一點所到達。

事實二:每一個強連通子圖上的奶牛們意見都一致。

因此,在本題中,我們可以把每一個強連通子圖(及它所代表的奶牛群)當做一個整體來看待。若把每個強連通子圖看成由該子圖的所有頂點能過頂點壓縮 ( Vertex Contraction )成為一個超級頂點,從而得到一個新的超級圖,則容易證明,

事實三:超級圖是一個有向無環圖 (DAG)。

強連通子圖的出度定義為其對應的超級頂點在超級圖上的出度,它的鄰居為其對應的超級頂點在超級圖上的鄰居所對應的強連通子圖。如果一個強連通子圖的出度為0,則稱其為 匯(sink)

。由事實一可知,如果超級圖上有至少兩個匯,則沒有奶牛是最受歡迎的。到目前為止,利用事實一,當沒有最受歡迎的奶牛時,我們可以快速給出答案。但是,如果圖沒有匯,則該事實毫無用處,而且,我們還看不出其它的兩個事實能怎麼用來改進演算法。不過,下面的事實給我們帶來了希望。

事實四:任何有限 DAG 都有至少一個匯。

這個事實也不是太明顯,略加證明一下。用反證法。假設沒沒有匯。則所有的頂點都至少一條出邊,即至少有一個鄰居。現在,任取一點 v1。從 v1 出發,任取 v1 的一個鄰居 v2。由於每點都有出邊,因此,該過程可以進行下去,從而得到路徑 v1,v2,...,vn+1,其中 n 為該圖的頂點數量。由於路徑上有 n+1 個頂點,從而必然有至少兩個頂點 vi

和 vj (i<j) 是相同的,從而 vi,vi+1,...,vj 構成了一個環,這與該圖為 DAG 相矛盾。證畢。

由於超級圖上存在至少一個匯,而匯是出度為 0 的頂點,即它認為其它的奶牛群都不受歡迎。因此,如果一個頂點不是匯,則它不可能是最受歡迎的!所以,我們只要考慮原來圖上的匯即可。而根據事實一,我們最多考慮一個匯,因為,當有至少兩個匯時,答案為 0。綜合上述討論,可以設計如下演算法:

 

第一步和第二步都只需要 O(V+E) 的時間,第三步只需要 O(V),對於第五步,可以 O(V+E) 的時間先轉置一下超級圖,然後看看該匯點是否能夠通過轉置了的超級圖上的邊到達所有其它頂點,這也需要 O(V+E)。因此,總的時間複雜度為 O(V+E)。

到此,問題得到很好解答。但是,並不完美。上述演算法,要求強連通子圖,還要求超級圖,甚至超級圖的轉置!這需要多遍掃描原圖和超級圖,以及多遍的深度優先搜尋!對於完美主義者來說,這似乎不能接受。雖然時間複雜度沒辦法再有質的降低,但是,我們可以試著降低複雜度的常數係數,同時使算優雅而容易實現。

首先,最“刺眼”的是第五步。在這一步中,需要轉置超級圖,還需要對轉置的超級圖進行一次深度優先搜尋。能不能去掉這一步?也即是,如果 DAG 上存在惟一的 匯,則能不能有快速的辦法判斷該匯是否是最受歡迎的?現在,讓我們來看本題中,最漂亮的結論。

事實五:如果有限 DAG只有一個匯,則該匯能夠被其它的任一頂點所到達。

這個事實並不明顯,因此需要簡單證明一下。用反證法。假設原圖 G 存在至少一個頂點 u,不能到達匯 t。把圖上的所有頂點分成兩類。第一類為包含 t 以及能夠到達 t 的所有頂點;第二類不能夠到達 t 的。顯然,第一類至少有頂點 t,而第二類至少有頂點 u,所以均不為空。因此,第二類的所有頂點構成一個非空的子圖 G',且該子圖也是一個 DAG,從而由事實四,存在至少一個匯 s,即 s 沒有邊到第二類頂點中的任何頂點。我們斷言,s 也是 G 的匯。這是,因為 s 不可能有邊連到第一類中的任何頂點 v,否則 s->v-->t (s->v 表示有一條邊從 s 到 v,而 v--> t 表示有一條路徑從 v 到達 t )為一條路徑從 s 到 t,這與 s 為第二類頂點相矛盾。因此,s 沒有邊指向 G 中的其它任何頂點,也即 s 是 G 的一個匯。但這與 G 只有一個匯相矛盾,因此,假設不成立,從而不存在頂點 u 不能到達匯 t,即 t 能夠被任何其它頂點所到達。

這樣,我們就可以把第五步省掉了。在剩下的四步中,最重要的就是一個強連通子圖的出度是否為0。通過修改求強連通子圖的 Tarjan 演算法,可以在一遍的深度優先搜尋中一起判斷出求得的強連通子圖出度是否為 0。這樣,我們也就無需建立原圖的超級圖了,從而只需要一遍深度優先搜尋即可以解決本題。這樣,問題才算得到比較完美的解答。

 

總結:有些題就是要深入挖掘才能找到漂亮的解法,而一些數學理論和性質往往在深入挖掘的過程中發揮作用,本題就是一例。這類問題也是本人比較喜歡的一類:通過分析題目的一些性質和結合一些數學理論,從而找到優雅漂亮的解法。