接上文:http://blog.csdn.net/jj12345jj198999/article/details/6610971
拓撲排序【Q4】
假設這裡有一系列的任務,這些任務每次只能執行其中一個。其中有一些任務要依賴其他任務的完成,如果其他任務沒有完成則這些任務不可能開始執行。已知所有的依賴關係,我們想找到一個符合依賴關係的任務安排計劃表。(即每一個被計劃執行的任務只有在它依賴的任務全部完成時才可以開始執行)我們想要設計一種能夠迅速產生出這麼一個計劃表的演算法。該問題也就是拓撲排序。任務和他們的依賴關係能夠通過一幅有向圖得到展現。一個有向圖擁有一個頂點的集合V(與例子中的任務相對應),以及一個由一對頂點構成的邊的集合E。如果一個與v對應的任務必須在一個與w對應的任務之前執行,那麼圖中就存在一條從v到w的邊(表示(v,w)∈E)。該圖一定為無環圖,否則環上的任務將永遠不可能開始執行。這裡給出了使用圖來說明問題的簡單描述。
問題:給定一個有n個頂點的有向非循環圖G=(V,E),這些頂點從1到n進行編號,因此如果頂點v被標記為k,那麼頂點v可以通過一條直接路徑到達所有編號大於k的頂點。(一條路徑是一系列點的序列,這些點v1,v2...vk通過邊(v1,v2),(v2,v3)...(vk-1,vk)相連)
我們再一次嘗試依據規模更小的問題來解決這個問題。考慮一個更小問題的直接做法是移去一個頂點。換句話說,通過下面的方法可以看到歸納法蘊含在頂點的數量之中。
歸納假設1:我們已經知道如何按照上面描述的條件用n-1個頂點為所有的圖做上標記。
只有一個頂點的最基本的情況是很簡單的。如果n>1,我們可以移去一個頂點,然後嘗試使用歸納假設,再嘗試去拓展標記。我們首先需要核實的一點是移除一個頂點後的問題和原來的問題是一樣的(除了更小的規模外)。擁有一個一樣的問題很必要,否則歸納假設將無法使用。例子中唯一假設是圖不是循環圖表。由於移除一個頂點不可能產生一個循環圖表,那麼這種縮減是可行的。
這種縮減的問題在於儘管假設可以使用但我我們不清楚如何去拓展解決方案,即怎麼去標記移除的頂點。我們解決該問題的方案是精心選擇頂點v。由於移去任何一個頂點產生的規模更小的問題都是符合要求的,所以我們可以任意選擇一個頂點作為第n個頂點。因此,我們應該移除那些最容易擷取標記的點。一個明顯的選擇是那些沒有依賴關係的頂點(任務),也就是該頂點的入度(指向該點的邊數)為0。可以把該頂點標記為1,這不會帶來什麼錯誤。
但是,我們總能找到一個入度為0的點嗎?答案按直覺是肯定的,但我們必須從某個地方開始。毫無疑問的是,如果所有的頂點都有大於0的入度我們可以用各種方式遍曆圖而且永遠不會停止。但是由於只有有限數量的頂點需要我們去迴圈尋找,這與我們的假設是相矛盾的。(同理我們也可以從出度為0的頂點開始尋找,然後把該頂點標記為n)剩下的演算法就很清晰了。移除選擇的頂點的相鄰邊,剩下的圖依然是無環圖,再用2到n標記圖的剩餘部分。由於我們需要用2到n而不是1到n-1標記剩下的圖,我們需要對歸納假設做點改動。
歸納假設2:我們知道依據問題的條件如何使用n-1不同標記的集合去標記一個擁有n-1個頂點的圖。
下面給出與之對應的演算法
拓撲排序演算法
{G={V,E}:一個有向非循環圖};
begin
對所有的頂點的入度初始化;
{可以通過深度優先搜尋}
G_label:=0;
for i:=1 to n do
if vi.indegree=0 then put vi in Queue;
repeat
remove vertex v from Queue;
G_label:=G_label + 1;
v_label:=G_label;
for all edges(v,w) do
w.indegree:=w.ingegree-1;
if w.indegree=0 then put w in Queue
until Queue is empty
end;
複雜度:初始化入度計數器需要O(|V|+|E|)時間(例如在例子中使用深度優先搜尋)。找到一個入度為0的點要花費常數時間(訪問隊列)。每一條邊(v,w)被考慮一次(當v從隊列中被取出時)。因此,計數器需要更新的次數的多少就是圖中邊數目的多少。因此演算法的執行時間就是輸入規模的線性時間O(|V|+|E|)。
總結:這是另一個使用歸納法直接設計演算法的例子。這裡的技巧在於明智選擇歸納序列。我們不是武斷地縮減問題規模,而是選擇移除一個特殊的頂點。任何給定的問題的規模都可以用很多可能的方法加以縮減。思想就在於探尋各種各樣的選擇然後測試產生的演算法。我們從多項式計算這個例子中看到從左向右要比從右向左好。另一個通常的可能性是對從上往下和從下往上進行比較。同樣也可能每次遞增2而不是遞增1,當然還有更多的可能情況。有時最好的歸納序列甚至對於所有的輸入來說也是不盡相同的。設計一個特殊的演算法去尋找一個對問題執行規模縮減的最好的方法有時是值得的。