拓扑排序学习笔记

什么是拓扑排序

对一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
摘自百度百科

用通俗易懂的语言讲,就是对一个 有向无环图 通过一系列操作得到一个序列,该序列中的每一个元素都没一条指向他前面的元素的边。

怎么进行拓扑排序


上文说到要对一个 DAG 进行一系列操作,那么这一系列操作是什么呢。
从拓扑序的性质来看,DAG 中的每一条边都是从前面的元素指向后面的元素,那么最前面的元素显然是没有入度的,那么首先我们在建图的时候,要统计每个点的入度,建完图我们可以扫一遍每个元素,将每一个入度为 0 0 0 的点压入队列。
将全部的入度为 0 0 0 的点压入队列后,我们可以依次将这些点从图中删去。每删去一个点,把以他为顶点的边也删去,把这条边连着的另一顶点的入度减去 1 1 1 ,如果这个点的入度也为 0 0 0,就将他压入队列,知道队列里的元素为空。每次从队列里取出要删的点时,用一个数组将其记录,最后就可以得到这个图的拓扑序了。

代码实现:

#include<bits/stdc++.h>
#define reg register
#define ri reg int
using namespace std;
const int Maxn=5*1e5+5;
int n,m;
int tot,head[Maxn];
int In[Maxn];
int Ans[Maxn],cnt;
struct node{
	int v,nxt;
}edge[Maxn];

inline void Add_edge(int u,int v) {
	edge[++tot].v=v;
	edge[tot].nxt=head[u];
	head[u]=tot;
}

queue<int> q;

int main(){
	scanf("%d%d",&n,&m);
	for(ri i(1),u,v;i<=m;++i) {
		scanf("%d%d",&u,&v);
		Add_edge(u,v);
		++In[v];
	}
	for(ri i(1);i<=n;++i) 
		if(In[i]==0) 
			q.push(i);
	while(!q.empty()) {
		ri now=q.front();
		q.pop();
		Ans[++cnt]=now;
		for(ri i(head[now]) ;i ;i=edge[i].nxt) {
			ri v=edge[i].v;
			--In[v];
			if(In[v]==0) q.push(v);
		}
	}
	for(ri i=1;i<=cnt;++i) printf("%d ",Ans[i]); 
	return 0;
}

注意


只有有向无环图才能拓扑排序,每张图的拓扑序不唯一。

例题

LuoguP4017

LouguP5603

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值