拓扑排序模板专题

拓扑排序是对有向无环图(DAG)进行排序,从而找到一个序列。该序列满足对于任意一对不同的顶点u,v∈V,若G中存在一条从u->v的边,则在此序列中u在v前面。

拓扑排序也可以用来判断一个有向图是否存在环。

有两种算法可以求得该序列:

1.Kahn算法。

其实就是不断的寻找有向图中没有前驱(入度为0)的顶点,将之输出。然后从有向图中删除所有以此顶点为尾的弧。重复操作,直至图空,或者找不到没有前驱的顶点为止。

该算法还可以判断有向图是否存在环(存在环的有向图肯定没有拓扑序列),通过一个count记录找出的顶点个数,如果少于N则说明存在环使剩余的顶点的入度不为0。(degree数组记录每个点的入度数)

#include<bits/stdc++.h>
#define N 100010
using namespace std;
namespace program{
	queue<int>q;
	list<int>ans;
	int Next[N],head[N],to[N],tot=0;
	int in1[N],n,m;
	inline void init(){
		tot=0;
		memset(in1,0,sizeof in1);
		memset(head,-1,sizeof head);
	}
	inline void add(int u,int v){
		tot+=1;
		Next[tot]=head[u];
		to[tot]=v;
		head[u]=tot;
	}
	inline bool Kahn(){
		int cnt=0;
		while(!q.empty()){
			int k=q.front();
			q.pop();
			cnt+=1;
			ans.push_back(k);
			for(int i=head[k];i^(-1);i=Next[i]){
				in1[to[i]]-=1;
				if(!in1[to[i]])
					q.push(to[i]);
			}
		}
		if(cnt^n)
			return 0;
		return 1;
	}
	inline void work(){
		int u,v;
		cin>>n>>m;
		init();
		for(int i=1;i<=m;i++){
			cin>>u>>v;
			add(u,v);
			in1[v]+=1;
		}
		for(int i=1;i<=n;i++){
			if(!in1[i])
				q.push(i);
		}
		if(Kahn()){
			list<int>::iterator it;
			for(it=ans.begin();it!=ans.end();it++)
				cout<<*it<<" ";
			return;
		}else{
			puts("NO");
		}
	}
}
int main(){
	program::work();
	return 0;
}

2.基于DFS的求解方法。

算法导论对于该种方法讲述的比较详细,由于它用的单链表存边,下面我只贴一份自己的模板代码。

思想基于:DFS时候,遇到u->v边,通过在DFS函数快退出时将结点加入到List中实现v在序列的位置始终在u的前面。反向序列即为所求的拓扑序列。

#include<bits/stdc++.h>
#define N 100010
using namespace std;
namespace program{
	int tot,head[N],Next[N],to[N];
	bool limit[N];
	int n,m;
	list<int>ans;
	inline void init(){
		tot=0;
		memset(limit,0,sizeof limit);
		memset(head,-1,sizeof  head);
	}
	inline void add(int u,int v){
		tot+=1;
		to[tot]=v;
		Next[tot]=head[u];
		head[u]=tot;
	}
	inline void dfs(int k){
		limit[k]=1;
		for(int i=head[k];i^-1;i=Next[i]){
			if(!limit[to[i]])
				dfs(to[i]);
		}
		ans.push_back(k);
	}
	inline void work(){
		int u,v;
		cin>>n>>m;
		init();
		for(int i=1;i<=m;i++){
			cin>>u>>v;
			add(u,v);
		}
		for(int i=1;i<=n;i++)
			if(!limit[i])
				dfs(i);
		list<int>::reverse_iterator it;
		for(it=ans.rbegin();it!=ans.rend();it++)
			cout<<*it<<" ";
		puts("");
		return;
	}
}
int main(){
	program::work();
	return 0;
}
点赞