【代码超详解】UVA 10305 Ordering Tasks 任务排序(拓扑排序)

博客详细解析了UVA 10305任务排序问题,介绍了如何利用拓扑排序解决任务依赖顺序。通过建立有向图,阐述了拓扑排序算法的步骤,包括统计每个任务的入度,找出并完成入度为0的任务,以及在过程中处理环的存在情况。同时,博主分享了一段AC代码,并针对代码中一处可能导致死循环的疑点进行了探讨。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、题目描述

John 有一些任务要做,但是部分任务要求必须完成之前的某些任务才能进行。
输入有若干测试样例,每个样例第一行是两个整数 n 和 m ,其中 1 ≤ n ≤ 100,m 。n 代表任务数量,每个任务编号从 1 开始一直到 n 。接下来 m 行描述任务的先后关系。每行两个数 i 和 j 用一空格分隔,表示任务 j 必须在任务 i 之后完成。
当 m = n = 0 时输入结束。
对每个输入,输出一行 n 个数,空格隔开,表示任务完成的先后顺序。如果有多个解,输出任意一个。

二、算法分析说明与代码编写指导

将任务的先后顺序画成有向边 <u, v> ,表示任务 u 必须在任务 v 之前完成。于是我们可以用拓扑排序来完成求解。对一个图进行拓扑排序,相当于:将这些有向边都画在一条有向线段上,并将边的方向与该线段的方向重合,那么对任意一条有向边,其起点指向终点的方向都与该线段的方向相同。
这条有向线段及其上面的点的相对位置整体可以看成任务完成的相对时间顺序。
拓扑排序的算法:
统计每个点的入度(指向该点的有向边的数量 / 该点作为有向边的终点的次数),将入度为零的点先找出来,输出,然后遍历以该点为起点的边,将这些边的终点的入度 -1 ,并将该点和这些边从图中删除。
重复上述步骤,直到全部点都删除。

如果途中出现了找不到入度为 0 的点的情况,证明剩余点都有边“进入”,该图存在环,无解(也就是说剩下的任务无法按照要求的先后顺序完成)。
这个算法的原理可以说成:每次将没有要求之前必须做完某任务的任务先找出来,优先完成,这样需要在这些任务之后完成的任务就在这些任务后面了。

根据这个算法,我们用链式前向星表示这样的边,然后对添加边的函数稍作修改,以便统计每个点的入度。原始模板在这里:https://blog.youkuaiyun.com/COFACTOR/article/details/97052588
在添加有向边函数 AddEdge 中增加一步:
++indegree[vtx_v];
用于累加点 v 的入度。v 是每条有向边指向的点。
首先将全部任务都当作点,添加到集合 s 中。然后遍历 s ,如果一个点的入度是零,就遍历其所有的边。这里用 head 数组定位要找的边的起始位置,然后用每条边的 Next 成员定位下一条从该点出发的边。对全部这样的边指向的终点,入度 -1。然后将点和边删除。删除以节点 u 为起始点的边可以置零 head[u] ,这就相当于无法通过 head[u] 找到从 u 出发的边,等效于没有从节点 u 出发的边。删除节点 u 就在集合 s 中删除,这样在遍历集合 s 时就再也访问不到这个节点了。
AC 代码(0 ms):

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<set>
#pragma warning(disable:4996)
using namespace std;
struct Edge {
   
    unsigned short NextStoPos = 0; unsigned char to = 0; };
Edge edge[4951]; unsigned short head[101], indegree[101
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值