ACM第四專題—圖算法總結

  圖的基本知識 
  頂點:圖中的數據元素稱爲頂點.
有向圖:有方向的圖叫有向圖.
無向圖:沒有方向的圖叫無線圖.
完全圖:有n(n-1)/2條邊的無向圖稱爲完全圖.
有向完全圖:具有n(n-1)條弧的有向圖稱爲有向完全圖.
稀疏圖:有很少條邊或弧的圖稱爲稀疏圖,反之稱爲稠密圖.
權:與圖的邊或弧相關的數叫做權(weight).


1. Relaxation(鬆弛操作): 
procedure relax(u,v,w:integer);//多數情況下不需要單獨寫成procedure。 
begin 
  if dis[u]+w<dis[v] then 
    begin 
      dis[v]:=dis[u]+w; 
      pre[v]:=u; 
    end 
end; 
2. Dijkstra 
1) 適用條件&範圍: 
a) 單源最短路徑(從源點s到其它所有頂點v); 
b) 有向圖&無向圖(無向圖可以看作(u,v),(v,u)同屬於邊集E的有向圖) 
c) 所有邊權非負(任取(i,j)∈E都有Wij≥0); 
2) 算法描述: 
a) 初始化:dis[v]=maxint(v∈V,v≠s); dis[s]=0; pre[s]=s; S={s}; 
b) For i:=1 to n 
1.取V-S中的一頂點u使得dis[u]=min{dis[v]|v∈V-S} 
2.S=S+{u} 
3.For V-S中每個頂點v do Relax(u,v,Wu,v) 
c) 算法結束:dis[i]爲s到i的最短距離;pre[i]爲i的前驅節點 
3) 算法優化: 
使用二叉堆(Binary Heap)來實現每步的DeleteMin(ExtractMin,即算法步驟b中第1步)操作,算法複雜度從O(V^2)降到O((V+E)㏒V)。推薦對稀疏圖使用。 
使用Fibonacci Heap(或其他Decrease操作O(1),DeleteMin操作O(logn)的數據結構)可以將複雜度降到O(E+V㏒V);如果邊權值均爲不大於C的正整數,則使用Radix Heap可以達到O(E+V㏒C)。但因爲它們編程複雜度太高,不推薦在信息學競賽中使用。 
3. Floyd-Warshall 
1) 適用範圍: 
a) APSP(All Pairs Shortest Paths) 
b) 稠密圖效果最佳 
c) 邊權可正可負 
2) 算法描述: 
a) 初始化:dis[u,v]=w[u,v] 
b) For k:=1 to n 
For i:=1 to n 
For j:=1 to n 
If dis[i,j]>dis[i,k]+dis[k,j] Then
Dis[I,j]:=dis[I,k]+dis[k,j]; 
c) 算法結束:dis即爲所有點對的最短路徑矩陣 
3) 算法小結: 
此算法簡單有效,由於三重循環結構緊湊,對於稠密圖,效率要高於執行|V|次Dijkstra算法。時間複雜度O(n^3)。 
考慮下列變形:如(I,j)∈E則dis[I,j]初始爲1,else初始爲0,這樣的Floyd算法最後的最短路徑矩陣即成爲一個判斷I,j是否有通路的矩陣。更簡單的,我們可以把dis設成boolean類型,則每次可以用“dis[I,j]:=dis[I,j]or(dis[I,k]and dis[k,j])”來代替算法描述中的藍色部分,可以更直觀地得到I,j的連通情況。 
與Dijkstra算法類似地,算法中藍色的部分可以加上對Pre數組的更新,不再贅述。 
4. Prim (Dijksta的推廣)
1) 適用範圍: 
a) MST(Minimum Spanning Tree,最小生成樹) 
b) 無向圖(有向圖的是最小樹形圖) 
c) 多用於稠密圖 
2) 算法描述: 
a) 初始化:dis[v]=maxint(v∈V,v≠s); dis[s]=0; pre[s]=s; S={s};tot=0 
b) For i:=1 to n 
1.取頂點v∈V-S使得W(u,v)=min{W(u,v)|u∈S,v∈V-S,(u,v)∈E} 
2.S=S+{v};tot=tot+W(u,v);輸出邊(u,v) 
3.For V-S中每個頂點v do Relax(u,v,Wu,v) 
c) 算法結束:tot爲MST的總權值 
注意:這裏的Relax不同於求最短路徑時的鬆弛操作。它的代碼如下: 
procedure relax(u,v,w:integer);        //鬆弛操作 
begin 
  if w<dis[v] then 
    begin 
      pre[v]:=u; 
      dis[v]:=w; 
    end; 
end; 
可以看到,雖然不同,卻也十分相似。 
3) 算法優化: 
使用二叉堆(Binary Heap)來實現每步的DeleteMin(ExtractMin)操作 
算法複雜度從O(V^2)降到O((V+E)㏒V)。推薦對稀疏圖使用。 
使用Fibonacci Heap可以將複雜度降到O(E+V㏒V),但因爲編程複雜度太高,不推薦在信息學競賽中使用。 
(不要問我爲什麼和Dijkstra一樣……觀察我的prim和dijkstra程序,會發現基本上只有relax和輸出不一樣……) 
5. Kruskal 
1) 適用範圍: 
a) MST(Minimum Spanning Tree,最小生成樹) 
b) 無向圖(有向圖的是最小樹形圖) 
c) 多用於稀疏圖 
d) 邊已經按權值排好序給出 
2) 算法描述: 
基本思想:每次選不屬於同一連通分量(保證無圈)且邊權值最小的2個頂點,將邊加入MST,並將所在的2個連通分量合併,直到只剩一個連通分量 
3) 算法實現: 
a) 將邊按非降序排列(Quicksort,O(E㏒E)) 
b) While 合併次數少於|V|-1 
i. 取一條邊(u,v)(因爲已經排序,所以必爲最小) 
ii. If u,v不屬於同一連通分量 then 
1) 合併u,v所在的連通分量 
2) 輸出邊(u,v) 
3) 合併次數增1;tot=tot+W(u,v) 
c) 算法結束:tot爲MST的總權值 
4) 分析總結: 
檢查2個頂點是否在同一連通分量可以使用並查集實現(連通分量看作等價類)。 
我們可以看到,算法主要耗時在將邊排序上。如果邊已經按照權值順序給出,那太棒了…… 
另外一種可以想到的實現方法爲:O(n)時間關於邊權建二叉小根堆;每次挑選符合條件的邊時使用堆的DelMin操作。這種方法比用Qsort預排序的方法稍微快一些,編程複雜度基本一樣。附程序。 
另外,如果邊權有一定限制,即<=某常數c,則可以使用線性時間排序以獲得更好的時間效率。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章