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(* ̄▽ ̄*)ブ

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值