PAT_甲級_1146 Topological Order (25point(s)) (C++)【拓撲排序】

目錄

1,題目描述

 題目大意

知識補充——拓撲排序

問題的引入——AOV網

拓撲排序

算法實現

2,思路

3,AC代碼

4,解題過程


1,題目描述

Sample Input:

6 8
1 2
1 3
5 2
5 4
2 3
2 6
3 4
6 4
5
1 5 2 3 6 4
5 1 2 6 3 4
5 1 2 3 6 4
5 2 1 6 3 4
1 2 3 4 5 6

 

Sample Output:

3 4

 題目大意

給出一個有向圖,判斷給出的序列是否爲拓撲序列。

 

知識補充——拓撲排序

(以下內容來自百度百科,晴神筆記) 

問題的引入——AOV網

一個較大的工程往往被劃分成許多子工程,我們把這些子工程稱作活動(activity)。在整個工程中,有些子工程(活動)必須在其它有關子工程完成之後才能開始,也就是說,一個子工程的開始是以它的所有前序子工程的結束爲先決條件的,但有些子工程沒有先決條件,可以安排在任何時間開始。爲了形象地反映出整個工程中各個子工程(活動)之間的先後關係,可用一個有向圖來表示,圖中的頂點代表活動(子工程),圖中的有向邊代表活動的先後關係,即有向邊的起點的活動是終點活動的前序活動,只有當起點活動完成之後,其終點活動才能進行。通常,我們把這種頂點表示活動、邊表示活動間先後關係的有向圖稱做頂點活動網(Activity On Vertex network),簡稱AOV網。

拓撲排序

拓撲排序是將有向無環圖G的所有頂點排成一個線性序列,使得對圖G中的任意兩個頂點u、v,如果存在邊u->v,那麼在序列中u- -定在v前面。這個序列又被稱爲拓撲序列。

算法實現

  1. 定義一個隊列Q,並把所有入度爲0的結點加入隊列。
  2. 取隊首結點,輸出。然後刪去所有從它出發的邊,並令這些邊到達的頂點的入度減1,如果某個頂點的入度減爲0,則將其加入隊列。
  3. 反覆進行2操作,直到隊列爲空。如果隊列爲空時入過隊的結點數目恰好爲N,說明拓撲排序成功,圖G爲有向無環圖;否則,拓撲排序失敗,圖G中有環。

可使用鄰接表實現拓撲排序。顯然,由於需要記錄結點的入度,因此需要額外建立一一個數組inDegree[MAXV],並在程序一開始讀 入圖時就記錄好每個結點的入度。

 

2,思路

題目比較簡單,只是判斷序列是否爲拓撲序列即可。

1,構建圖,並統計每個節點的入度;

2,針對給定的序列,依次判斷一個點,若當前點入度爲0,則將其所有的鄰接點入讀減一,繼續判斷下一個;否則,即可判定不是拓撲序列;

 

3,AC代碼

#include<bits/stdc++.h>
using namespace std;
int N, M, K, inDegree[1005], inTemp[1005];          //Nd頂點數 M有向邊數 K查詢數目
vector<int> ans, graph[1005];
bool judge(int temp[]){                             // 判斷是否爲拓撲序列 true是 false不是
    memcpy(inTemp, inDegree, (N+1) * sizeof(int));  // !!!節點編號從1開始 所以是N+1
    for(int i = 0; i < N; i++){
        if(inTemp[temp[i]] == 0){
            for(auto it : graph[temp[i]])
                inTemp[it]--;                       // 該節點temp[i]對應的所有相鄰節點入度減一
        }else return false;
    }
    return true;
}
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    scanf("%d%d", &N, &M);
    int a, b;
    for(int i = 0; i < M; i++){
        scanf("%d%d", &a, &b);
        graph[a].push_back(b);
        inDegree[b]++;                              // 有向邊指向的頂點入度加一
    }
    scanf("%d", &K);
    int temp[N];
    for(int i = 0; i < K; i++){
        for(int j = 0; j < N; j++)                  // 獲取拓撲序列
            scanf("%d", &temp[j]);
        if(!judge(temp))
            ans.push_back(i);
    }
    for(int i = 0; i < ans.size(); i++)
        printf("%d%c", ans[i], i == ans.size()-1 ? '\n':' ');
    return 0;
}

4,解題過程

一發入魂o(* ̄▽ ̄*)ブ

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章