算法学习系列(二十一):拓扑排序

发布时间:2024年01月16日

引言

这个拓扑排序大家应该都听说过,用的地方也是很多,考研和面试也是经常考,其实这个排序算法的思想比较简单,应用的话就是可以用来判断一个图中是否存在一个环,本文主要是介绍拓扑排序的思想,以及一个简单的模板题,来帮助了解什么是拓扑排序,以及怎么写。

一、拓扑排序概念

英文名:topsort,叫拓扑排序纯属是音译,实际没啥具体含义哈
只有有向图无环图存在拓扑序列

思想:找入度为0的点加入序列,然后更新剩余的点,再找入度为零的点再次更新,直至图中所有的点全部加入到序列中,然后加入序列的顺序就是拓扑排序的顺序啦!

二、代码模板


const int N = 1e5+10;

int n, m;
int h[N], e[N], ne[N], idx;  //常规的链式存储法
int dist[N], q[N];  //dist[i]代表i号点的入度数

bool topsort()
{
    int hh = 0, tt = -1;
    
    for(int i = 1; i <= n; ++i)  //先把所有入度为0的点加入序列中
    {
        if(!dist[i]) q[++tt] = i;
    }
    
    while(hh <= tt)
    {
        auto t = q[hh++];
        
        for(int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            dist[j]--;  //将其与之相连点的入度减1
            if(!dist[j]) q[++tt] = j;  //若入度减为0则加入到队列中
        }
    }
    
    return tt == n - 1;  //若所有点都加入队列中,说明存在拓扑序列
}

//输出拓扑序列,刚好为加入到队列的顺序
if(topsort())
{
    for(int i = 0; i < n; ++i) printf("%d ", q[i]);
}

三、例题

给定一个 n 个点 m 条边的有向图,点的编号是 1到 n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 ?1。

若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。

输入格式
第一行包含两个整数 n 和 m。
接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 (x,y)。

输出格式
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。
否则输出 ?1。

数据范围
1≤n,m≤105

输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 1e5+10;

int n, m;
int h[N], e[N], ne[N], idx;
int dist[N], q[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

bool topsort()
{
    int hh = 0, tt = -1;
    
    for(int i = 1; i <= n; ++i)
    {
        if(!dist[i]) q[++tt] = i;
    }
    
    while(hh <= tt)
    {
        auto t = q[hh++];
        
        for(int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            dist[j]--;  
            
            if(!dist[j]) q[++tt] = j;
        }
    }
    
    return tt == n - 1;
}

int main()
{
    memset(h, -1, sizeof h);
    
    scanf("%d%d", &n, &m);
    
    while(m--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a,b);
        dist[b]++;
    }
    
    if(!topsort()) puts("-1");
    else for(int i = 0; i < n; ++i) printf("%d ", q[i]);
    
    return 0;
}

看一个用例还是可以的,然后这道题也AC了
在这里插入图片描述

文章来源:https://blog.csdn.net/weixin_60033897/article/details/135633981
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。