1. 程式人生 > >經典演算法之拓撲排序

經典演算法之拓撲排序

定義:

把AOV網(用定點表示活動,用弧表示活動間優先關係的有向圖)絡中各個頂點按照它們互相之間的優先關係排列成一個線性序列的過程叫做拓撲排序。

方法:

  1. 在有向圖中選一個沒有前驅的頂點並且輸出
  2. 從圖中刪除該頂點和所有以它為尾的弧,即刪除所有與它有關的邊。
  3. 重複上述兩步,直至全部頂點均已輸出;或者當圖中不存在無前驅的頂點為止。

例題:

首先我們找到無前驅頂點C1和C9,我們刪除掉C1,輸出C1,並刪除所有與C1相連的邊

接著再從C2,C4,C9這三個無前驅頂點中選擇一個刪除掉,我們刪除C2,輸出C2,並刪除所有與C2相連的邊

重複操作

最終得拓撲序列:C1--C2--C3--C4--C5--C7--C9--C10--C11--C6--C12--C8。

注意:拓撲序列並不唯一,C9--C10--C11--C6--C1--C12--C4--C2--C3--C5--C7--C8 也是一種拓撲序列。

程式碼實現:

#include <iostream>

using namespace std;
#define N 13
int main()
{
    int map[N][N]; //鄰接矩陣
    // 初始化矩陣的值全部為0表示各個頂點間沒有邊連線
    for(int i = 0; i <= N-1; i++){
        for(int j = 0; j <= N-1; j++){
            map[i][j] = 0;
        }
    }

    int a,b;  //定義兩個變數,用來輸入
    int v,l;  //頂點數和邊數

    cout << "請輸入頂點數:";
    cin >> v;
    cout << "請輸入邊數:";
    cin >> l;
    cout << "請輸入邊:" << endl;

    for(int i = 1; i <= l; i++){
            cin >> a >> b;
            map[a][b] = 1; // 表示頂點a指向頂點b的邊
    }
    cout << "鄰接矩陣如下所示\n" << endl;
    for(int i = 1; i <= N-1; i++){
        for(int j = 1; j <= N-1; j++){
            cout << map[i][j];
        }
        cout << endl;
    }

    int k; //用於計算度數
    int ID[N]; //用於存放入度
    for(int i = 1; i <= v; i++){  // 計算入度
        k = 0;
        for(int j = 1; j <= v; j++){
            if(map[j][i] == 1) //如果頂點j到頂點i有邊,則頂點i的入度+1
                k++;
        }
        ID[i] = k;
    }
    //1、在有向圖中選一個沒有前驅的頂點並且輸出
    cout << "\n\n拓撲序列: ";
    int count = 0;   //最後用來判斷是否所有的頂點輸出
    while(1){
        for(int i = 1; i <= v; i++){
            if(ID[i] == 0){
                cout << i << " ";  //輸出頂點
                count++;
                //2、從圖中刪除該頂點和所有以它為尾的弧,即刪除所有與它有關的邊。
                ID[i] = -1; //將此頂點入度設為-1,表示刪除
                for(int j = 1; j <= v; j++){
                    if(map[i][j] == 1){     //如果頂點j與頂點i有邊,則刪除這條邊,並且頂點j的入度-1
                        ID[j]--;
                    }
                }
            }
        }
        //3、重複上述兩步,直至全部頂點均已輸出;或者當圖中不存在無前驅的頂點為止。
        if(count == v){
            break;  //若count == 頂點數,表示所有頂點的入度都為-1,即所有的邊均已輸出,停止操作。
        }
    }
    return 0;
}

輸入:

12    16

1   2 
1   4
1   3
1   12
2   3
3   5
3   7
3   8
4   5
5   7
9   12
9   10
9   11
10  12
11  6
6   8

輸出:

拓撲序列:1 2 3 4 5 7 9 10 11 12 6 8