图论算法の拓扑排序
拓扑序定义
对于一个$DAG$(有向无环图)$G$,它的拓扑序是该图所有节点的一个线性序列,该序列必须满足使得图中的任意一对顶点$u$和$v$,若边$ (u,v) \in E(G) $,则$u$在线性序列中出现在$v$之前
算法流程
对于一个$DAG$:
- 将所有入度为0的节点加入队列中
 
- 每次将队首元素(节点)出队并将其所有的出边砍掉(即 把该出边所连节点的入度减一),这样以后如果出现了新的入度为0的节点,那么把他们加入队列,重复该步骤,直到队列为空
 
- 每次出队的队首元素的顺序就是该图的一种拓扑序(答案不唯一,因为可能会同时存在好几个入度为0的节点,他们互不影响)
 
举个例子,如下一张图
我们首先将入度为0的点入队(1、4),此时拓扑序还未构建

然后删去他们的出边,并判断出边所连节点是否入度为0
此时拓扑序为:1 4

发现2、5节点的入度变为0了,于是入队,重复上一步操作

此时拓扑序为:1 4 2 5
删去2 5节点的出边后,发现3 6节点入度变为0,于是入队

取出3 6之后,拓扑序为:1 4 2 5 3 6
这时发现7入度为0,于是入队

最后结束,拓扑排序最终结果为:1 4 2 5 3 6 7(答案不止这一种,可以很容易算出此题答案有8种)
实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
   | #include<bits/stdc++.h> using namespace std; struct Edge{  	int u,v,next; }e[100005];
  int n,m,cnt,head[100005],indeg[100005]; inline void addedge(int u,int v){  	e[++cnt].u=u; 	e[cnt].v=v; 	e[cnt].next=head[u]; 	head[u]=cnt; } int ans[100005],ccnt; inline void topo_sort(){  	queue<int> q; 	for(int i=1;i<=n;i++){  		if(indeg[i]==0){ 			q.push(i); 		} 	} 	while(!q.empty()){  		int u=q.front(); 		q.pop(); 		ans[++ccnt]=u;  		for(int i=head[u];i;i=e[i].next){  			int v=e[i].v; 			if(indeg[v]){  				indeg[v]--;  				if(indeg[v]==0){  					q.push(v);  				} 			} 		} 	} }
  int main(){ 	scanf("%d %d",&n,&m); 	for(int i=1;i<=m;i++){ 		int u,v; 		scanf("%d %d",&u,&v); 		addedge(u,v); 		indeg[v]++;  	} 	topo_sort(); 	for(int i=1;i<=ccnt;i++){  		cout<<ans[i]<<" "; 	} 	return 0; }
 
  | 
 
题意
- 给一个DAG图重新编号并排序,使得对于该序列中任意的两点$i$$j$且$i<j$,满足新编号$a[i]<a[j]$
 
题解
- 考虑反向建图做一个逆拓扑排序,并且使用优先队列维护每次出队的都是最大的编号的节点,同时逆向编号即可得出答案
 
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
   | #include<bits/stdc++.h> using namespace std;
  struct Edge{ 	int u,v,next; }e[1000005]; int n,m,cnt,head[1000005],indeg[1000005]; inline void addedge(int u,int v){ 	e[++cnt].u=u; 	e[cnt].v=v; 	e[cnt].next=head[u]; 	head[u]=cnt; } int ans[1000005]; inline void tpsort(){ 	priority_queue<int> q;  	for(int i=1;i<=n;i++){ 		if(indeg[i]==0){ 			q.push(i); 		} 	} 	int num=n; 	while(!q.empty()){ 		int u=q.top(); 		q.pop(); 		ans[u]=num--;  		for(int i=head[u];i;i=e[i].next){ 			int v=e[i].v; 			if(indeg[v]){ 				indeg[v]--; 				if(indeg[v]==0){ 					q.push(v); 				} 			} 		} 	} 	 } int main(){ 	scanf("%d %d",&n,&m); 	for(int i=1;i<=m;i++){ 		int u,v; 		scanf("%d %d",&u,&v); 		addedge(v,u); 		indeg[u]++; 	} 	tpsort(); 	for(int i=1;i<=n;i++){ 		printf("%d ",ans[i]); 	} 	return 0; 	 } 
 
  |