1. 程式人生 > >拓補排序

拓補排序

結點 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了,那麽意味著這個結點沒有前驅了,就把這個結點壓人棧。這樣不斷循環直到出現兩種情況:

  1. 棧彈完了後沒有邊剩余,那麽這樣我們就拓補排序結束

  2. 如果棧彈完了仍有結點沒有排完,那麽這樣就說明這個圖中有環 ( 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;

}

拓補排序