拓扑排序详解&pta-任务调度的合理性(25 分)

拓扑排序在cccc赛前学习的一个小知识点,觉得蛮有意思的,当时看陈越姥姥讲的数据结构,姥姥把拓扑排序比作文艺青年的排序,我觉得有必要记录下这个知识点。

直接用姥姥的例子吧,计算机课程排课。

学习某一门课程时,必须提前学其他的一些课程才能学这门课程,这就是预修课程,例如c3数据结构的预修课程的c1和c2,这就是说学习数据结构之前必须先学习程序设计基础和离散数学根据每个课程的预修修课程画图可以形成一张图,称为AVO网络。

 

*拓扑序的文字概念:如果图中从v到w有一条有向路径,则v一定排在w之前。满足此条件的顶点序列称为一个拓扑序。

*获得一个拓扑序的过程就是拓扑排序。

*AOV如果有合理的拓扑序,则必定是有向无环图(Directed Acyclic Graph, DAG)

这个已经排好的序列,就是拓扑序。

然后根据网络就可以排出拓扑序列

先排出没有预修课的顶点,即是没有前驱的顶点,排出后将边抹除。

首先将第一排没有前驱的顶点先全部输出,得到

重复这样的操作将所有的顶点按照次序输出

-----------------------------------------

-----------------------------------------

-----------------------------------------

-----------------------------------------

这样就完成了一次排课,也就是一次拓扑排序的过程;

总结一下这个过程,每次输出的定点是没有前驱的顶点,没有前驱的顶点的特点是什么?对于一个有向图来说,每一个定点有两个度,一个是入度另一个是出度,所谓没有前驱的定点就是入度为零的顶点。

基本的实现步骤

如果找未输出的入度为0的定点的算法是将所有的点扫描一遍,那么整个排序的复杂度为O(v^2)。

改进一下这个算法,降低一下复杂度:

*随时将入度变为0的顶点放到一个容器里。

 

时间复杂度变问O(|V|+|E|)。(??复杂度稳定吗)

这个算法还可以检测有向图是否为有向无环图(DAG)。

题目

这个题基本就是拓扑排序的模板题,当时不会拓扑排序,用其他方法也没写出来,想起来其他方法再补充吧。

直接贴代码吧。

5-4 任务调度的合理性   (25分)

假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。

比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和C程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如C程序设计和数据结构两门课,必须先学习前者。

但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务A依赖于子任务B,子任务B依赖于子任务C,子任务C又依赖于子任务A”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。你现在的工作是写程序判定任何一个给定的任务调度是否可行。

输入格式:

输入说明:输入第一行给出子任务数NN(\le 100≤100),子任务按1~NN编号。随后NN行,每行给出一个子任务的依赖集合:首先给出依赖集合中的子任务数KK,随后给出KK个子任务编号,整数之间都用空格分隔。

输出格式:

如果方案可行,则输出1,否则输出0。

输入样例1:

12
0
0
2 1 2
0
1 4
1 5
2 3 6
1 3
2 7 8
1 7
1 10
1 7

输出样例1:

1

输入样例2:

5
1 4
2 1 4
2 2 5
1 3
0

输出样例2:

0
 
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
vector<int>mp[110];
int ind[110];
int main(){
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        int k;cin>>k;
        for(int j=0;j<k;j++){
            int v;cin>>v;
            mp[i].push_back(v);
            ind[v]++;
        }
    }
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(ind[i]==0){
            q.push(i);
        }
    }
    int cnt=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<mp[u].size();i++){
            int v=mp[u][i];
            ind[v]--;
            if(ind[v]==0){
                q.push(v);
            }
        }
        cnt++;
    }
    if(cnt==n)
        cout<<1<<endl;
    else
        cout<<0<<endl;
    return 0;
}

 

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值