1146 Topological Order (25 分) 拓扑排序 判定

本文深入探讨了拓扑排序的概念及其在有向无环图中的应用,详细介绍了拓扑排序的定义、实现算法及验证方法,通过实例解析了如何确定一个图的拓扑排序。

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

也不写题干了,主要说说拓扑排序。

对一个有向图G,我们把满足下列要求的顶点序列叫做G的拓扑排序,一般来说,一个图的拓扑排序不唯一。

(1)拓扑排序中的,对每一个节点,它的后继节点都在该节点之后出现。
(2)如果两节点没有直接间接的前驱后继关系,则两节点在序列中先后顺序不限
(3)每个拓扑排序包含G的所有节点

有向无环图(简称DAG):没有回路的有向图叫做有向无环图。

比如下图(就是pat 甲级1146样例中的图)
图举例
样例给出了如下数据

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

由图可知,(序列号从0开始)序列3,4违反了规则,2在1之前(序列3),4在5之前(序列4)。

回到我们的对拓扑排序的解释,如何确定一个图的拓扑排序呢?可以采用这种算法:
(1)将图的入度为0的节点入队
(2)队首节点v出队,输出该节点v的值,它的后继节点w的入度均-1,并且每次-1时均判断w的入度是否为0,如果为0,同样入队。
(3)重复2步骤,直到图为空或者不再存在无前驱的节点。如果是后者,则图中存在环。

当然,队列也可以用栈替代。

回到这个题的解法,那就很简单了。由于拓扑排序算法运行时,每次输出的节点的入度都为0,所以,在用题目中给出的序列模拟算法执行过程时,每次输出的节点的出度必为0,否则就不是一个拓扑排序。

  • 如果有数组data* a,则vector<data> v(a,a+sizeof(a))就可以将整个数组复制到向量中,这是vector的一种构造方法,两个参数相当于指针

代码如下。

#include <bits/stdc++.h>
#define N 1005
using namespace std;
vector<int> vi[N],ans;		//vi是图的邻接表表示 
int din[N];
int main(){
    int n,m,k;
    scanf("%d%d",&n,&m);
    for (int i=0;i<m;i++)   {
        int a,b;
        scanf("%d%d",&a,&b);
        vi[a].push_back(b);
        din[b]++;
    } 
    scanf("%d",&k);
    for (int p=0;p<k;p++) {
        int flag=0;
        vector<int> tv(din,din+n+1);
        for (int i=0;i<n;i++)   {
            int t;
            scanf("%d",&t);
            if (tv[t]!=0)  flag=1;		//,入度非0,说明该序列不是拓扑排序 
            for (int j=0;j<(int)vi[t].size();j++)
                tv[vi[t][j]]--;		//vi[t][j]意为节点t的第j个后继节点 
        }
        if (flag)   ans.push_back(p);
    }
    printf("%d",ans[0]);
    for (int i=1;i<(int)ans.size();i++) printf(" %d",ans[i]);
    printf("\n");
    return 0;
}

复杂度:这我还真不会算了,但是应该小于等于O(k*n2)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值