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