拓補排序
阿新 • • 發佈:2018-07-12
結點 stream 試驗 直接 一個棧 cpp push int pre
模板題目:
題目來源
[POJ] Genealogical tree
題目描述:
求1到n的其中一種拓撲序,保證存在一種拓撲序。輸入格式是:第一行讀入n,接下來n行,第i+1行表示有由i指向其他點的邊,以0結尾。(直接一個0就是它沒有連向任何點)。
樣例輸入:
5
0
4 5 1 0
1 0
5 3 0
3 0
樣例輸出:
2 4 5 3 1
方法:
我們先輸入數據,再輸入的時候用一個數組num_indegree[i]來記錄結點i的入度(即進入這個結點的數量)。之後我們再找所有結點中入度為0的結點把它壓入一個棧node中。之後我們開始把棧中的結點彈出並輸出,並把這個彈出的結點所到的結點的入度減一,如果某個結點在這樣之後入度變為0了,那麽意味著這個結點沒有前驅了,就把這個結點壓人棧。這樣不斷循環直到出現兩種情況:
棧彈完了後沒有邊剩余,那麽這樣我們就拓補排序結束
如果棧彈完了仍有結點沒有排完,那麽這樣就說明這個圖中有環 ( ps:這個我沒有試驗過,正確性未知 )
代碼:
#include <iostream> #include <stack> #include <cstdio> #include <vector> #include <algorithm> using namespace std; const int N = 1e2+5; int n,k; int num_indegree[N]; stack <int> node; //存入度(即每個點進來的邊)為0的點 vector <int> graph[N]; void add(int x,int y){ graph[x].push_back(y); } void toposort(){ while(!node.empty()){ //如果棧非空 int u=node.top(); printf("%d ",u); node.pop(); vector <int> :: iterator it; for(it=graph[u].begin();it!=graph[u].end();it++){ num_indegree[*it]--; if(num_indegree[*it]==0) node.push(*it); } } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ int k; while(true){ scanf("%d",&k); if(k==0) break; add(i,k); num_indegree[k]++; //計算每個點的入度 } } for(int i=1;i<=n;i++){ if(num_indegree[i]==0){ //如果找到一個沒有前驅的點 node.push(i); //把入度為0的點進棧 } } toposort(); return 0; }
拓補排序