拓撲排序
1.一般應用
拓撲排序常用來確定一個依賴關系集中,事物發生的順序。例如,在日常工作中,可能會將項目拆分成A、B、C、D四個子部分來完成,但A依賴於B和D,C依賴於D。為了計算這個項目進行的順序,可對這個關系集進行拓撲排序,得出一個線性的序列,則排在前面的任務就是需要先完成的任務。
2.實現的基本方法
(1)從有向圖中選擇一個沒有前驅(即入度為0)的頂點並且輸出它.
(2)從網中刪去該頂點,並且刪去從該頂點發出的全部有向邊.
(3)重復上述兩步,直到剩余的網中不再存在沒有前趨的頂點為止.
3.C++版本實現
1 /*以鄰接矩陣Edge[A][B]=N存放圖信息:A指向B,權值為N*/ 2 /*假設不相連的邊的Edge==INT_MAX*/ 3 void Topo() 4 { 5 sort(Edge+1,Edge+N+1); 6 for (int i=1; i<=N; i++) 7 { 8 int j; 9 for (j=1; j<=N; i++) //vis為標記數組,標記是否已經存在在Topo數組中 10 if (!vis[j]&&!in[j]) //in數組表示的下標頂點的入度 11 { 12 Topo[i]=j; 13 vis[j]=1; 14 break; 15 } 16 for (int k=1;k<=N;k++) //將與j點相連的頂點的入度刷新 17 if (Edge[j][k]!=INT_MAX) 18 in[k]--; 19 } 20 }
4.反向建圖
拓撲排序並不一定唯一,有時會要求頂點數值大的盡量在前,這個時候應該反向建圖,再進行拓撲排序,來保證更多小數值頂點在后面。(貪心思想?)
Eg:HDU 4857 POJ 3687(反向建圖+拓撲排序)
5.優化
拓撲排序每次選擇一個頂點進入序列后,要更新所有與這個頂點相連的頂點的入度。而上面的代碼全是把所有的頂點都遍歷了一邊。
這里可以使用鄰接表或者鏈式前向星這一類數據結構,來記錄圖的信息,可以做到只遍歷與該頂點相連的頂點。
6.優先隊列實現
1 /*優先隊列+鄰接表實現拓撲排序*/ 2 void Topo() 3 { 4 priority_queue<int> que; 5 for (int i=1; i<=N; i++) //將入度為零的頂點壓入隊列 6 if (dis[i]==0) 7 que.push(i); 8 int p=N+1; 9 while (!que.empty()) 10 { 11 int tmp=que.top(); 12 que.pop(); 13 topo[--p]=tmp; //存入topo數組 14 int z=first[tmp]; 15 while (z!=-1) //鄰接表遍歷與tmp相連的頂點 16 { 17 dis[end[z]]--; //入度減一 18 if(!dis[end[z]]) que.push(end[z]); 19 z=next[z]; 20 } 21 } 22 }