拓扑序列
对一个有向无环图(Directed Acyclic Graph,简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前
AOV网(顶点活动网,Activity On Vertex network):顶点表示活动、边表示活动间先后关系的有向图。
Kahn算法
算法步骤
主要是循环执行以下两步,直到不存在入度为0的顶点为止。
(1) 选择一个入度为0的顶点并输出之;
(2) 从网中删除此顶点及所有出边。
循环结束后,若输出的顶点数小于网中的顶点数,则有回路,否则输出的顶点序列就是一种拓扑序列。
class Edge{
int to;
int cost;
}
class AOV{
int N;
int M;
Vector<Edge>[] graph;
int[] degree;
LinkedList<Integer> topology;//FIFO
void init(){
graph = new Vector[N];
degree = new int[N];
topology = new LinkedList<Integer>();
for (int i = 0; i < N; i++)
graph[i] = new Vector<Edge>();
}
boolean Kahn(){
Stack<Integer> stack = new Stack<Integer>();//storage the nodes of which degree is 0
for (int i = 0; i < N; i++) {
if(0 == degree[i])
stack.push(i);
}
int now = 0;
while (!stack.isEmpty()){
now = stack.pop();
topology.add(now);
for (int i = 0; i < graph[now].size(); i++) {
Edge edge = graph[now].get(i);
degree[edge.to]--;
if(0 == degree[edge.to])
stack.push(edge.to);
}
graph[now].clear();
}
if(topology.size() == N){
return true;
}else
return false;
}
}
基于DFS的拓扑排序
每次都沿着一条路径一直往下搜索,直到某个顶点没有了出度时,就加入拓扑序列中,然后往回走,所以我们就用DFS的这个思路,我们可以得到一个有向无环图的拓扑序列,其实很像Kahn算法的逆过程。
#include<iostream>
#include<stack>
using namespace std;
#define Max 9999
int graph[Max][Max];//一个有向图
int n,m;//结点数,边数
stack<int> topo;//栈存拓扑序列,先进后出
int vis[Max];//访问状态:-1正在访问,1访问结束,0未访问
bool dfs(int u)
{
vis[u]=-1;//正在访问
int i;
for(i=1;i<=n;i++)
if(graph[u][i]==1)//找边
{
if(vis[i]==-1)//访问两次,说明有环
return 0;
else
if(vis[i]==0)//未访问过
dfs(i);
}
vis[u]=1;//访问完成
topo.push(u);//将该点入栈
return true;
}
bool Topological_sort()
{
for(int i=1;i<=n;i++)//遍历每个结点
if(vis[i]==0)//未访问过
{
if(!dfs(i))
return false;
}
return true;
}
int main()
{
int u,v;
cin>>n>>m;
for(int i=0;i<m;i++)
{
cin>>u>>v;
graph[u][v]=1;
}
if(Topological_sort())//无环,输出拓扑序列
{
int size=topo.size();
for(int i=0;i<size;i++)
{
cout<<topo.top()<<" ";
topo.pop();
}
cout<<endl;
}
else
cout<<"有环"<<endl;
}