Topsort-稍微讲讲

拓扑排序:
首先拓扑排序适用于aov网,就是有向无环图。

这里插入一下链接:比较容易去进行理解。
top排序的图形讲解

结合王道的内容讲解去解释一下拓扑排序的条件:
(1)每个顶点出现且仅仅出现一次
(2)若顶点A在序列中,排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径

算法流程:
统计所有节点的入度,对于入度如果为0的点分离出来。

如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。
算法流程:
用队列来执行 ,初始化讲所有入度为0的顶点入队。
主要由以下两步循环执行,直到不存在入度为 0 的顶点为止

(1)选择一个入度为 0 的顶点,并将它输出;
(2)删除图中从顶点连出的所有边。
循环结束,

若输出的顶点数小于图中的顶点数,则表示该图存在回路,即无法拓扑排序,

否则,输出的就是拓扑序列 (不唯一)

虽然看起来很长,但是我觉得真的还是比较好理解的。
这里我顺便结合图去讲解一下:虽然不太建议去用特例去解释:
在这里插入图片描述
分析过程如下:
在a图中,我们不难发现入度=0的点为a和f。那么,如果存在拓扑排序的话,那么可能就要通过a和f或者拓扑序列。

得到拓扑过程如下(其实真的很类似于层序遍历):
我们拿到队首的元素,我们依次遍历单链表:a->c(此时再减去入度,那么如果d[c]==0,那么就是拓扑序列)->b.
注意为什么不先从a->b,因为b的入度为2,显然不是拓扑序列的一个小过程。

同理可以得出fde是另外一个环的拓扑序列。

//topsort的分析
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N=100010;
int n,m;
int h[N],e[N],ne[N],idx;
int d[N];//记录每一个点的入度
int top[N];//存储top序列
//头插法进行链表的插入
int cnt=1;//记录入队里面的个数
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
bool topsort(){
    
    queue<int> q;
    int t;
    
    //先把入度为0的点全部放在队列里面
    for(int i=1;i<=n;i++){
        if(d[i]==0) q.push(i);
    }
    //以上肯定就是一个个顶点,因为顶点的度都是为0
    //然后从度为0的点开始去进行一次遍历,其实就是一个链表的遍历
    while(q.size()){
        t=q.front();//取出队首的元素
        //根据队首的首部然后把首元素取出,然后一次遍历里面,存储起来
        top[cnt++]=t;
        q.pop();
        //根据的元素去遍历整条链表,删除图中从顶点连出的所有边
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            d[j]--;
            if(d[j]==0) q.push(j);
        }
    }
    //但是还有可能是存在单个或者多个环,那么就是不存在环了]
    if(cnt<n) return 0;
    else return 1;
}
int main(){
    cin>>n>>m;
    //初始化链表的头
    memset(h,-1,sizeof h);
    for(int i=0;i<m;i++){
        int a,b;cin>>a>>b;
        add(a,b);
        //以上构建出图的部分
        d[b]++;//b的度+1
    }
    //拓扑排序注意一下出度和入度就行了
    
    //现在要求做的是,如果不是拓扑排序,那么就输出-1
    //如果是拓扑排序的话,那么输出拓扑排序的过程
    if(topsort()==0) puts("-1");
    else{
       for(int i = 1;i <= n; ++i){
            cout << top[i] <<" ";
        } 
    }
    
    return 0;
}

例题还在做,稍后补充!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值