拓扑排序
定义:对一个有向无环图(Directed Acyclic Graph简称DAG) G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
通俗的说就是根据给出的部分排序信息得到全部顺序的操作。
注意:当有向图中存在有向环时,拓扑序列不存在,即不能对该图进行拓扑排序。
例如:
1>2 1>3 1>4 3>2 3>5 4>5 6>4 6>5
如图
我们发现6和1没有前驱,所以我们随机选一个输出(拓扑排序结果不唯一;也可利用队列或数组存储,在main函数中输出),我们先输出6,删除和6有关的边,得到如下结果:
我们发现1是没有前驱的,所以我们输出1(或存储),删除和1有关的边,得到如下图结果:
继续判断前驱为0的点,输出并删除与它有关的边,选择删除4(可存储;也可选择3),结果如下。
输出没有前驱的3(或者存储)并删除相关的边,结果如下图。
2和5 选择任意一个输出(或存储),拓扑排序完成。
一些拓扑排序基础题:
无前趋的顶点优先的拓扑排序方法
该方法的每一步总是输出当前无前趋(即入度为零)的顶点;利用数组模拟:
#include<stdio.h>//模拟队列
#include<string.h>
int n,m,w;
int s[120],book[120][120],line[120];
void topsort()
{
int k;
for(int j=0;j<n;j++)
{
for(int i=1;i<=n;i++)
{
if(s[i]==0)//入度为0
{
k=i;
break;
}
}
line[w++]=k;//进数组
s[k]=-1;
for(int i=1;i<=n;i++)
{
if(book[k][i]==1)
s[i]--;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
int a,b;w=0;
memset(book,0,sizeof(book));
memset(s,0,sizeof(s));
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
if(book[a][b]==0)
{
book[a][b]=1;
s[b]++;//入度加1
}
}
topsort();
printf("%d",line[0]);
for(int i=1;i<w;i++)
{
printf(" %d",line[i]);
}
return 0;
}
以上是利用数组模拟队列进行正序输出;
接下来是拓展:
无后继的顶点优先拓扑排序方法
该方法的每一步均是输出当前无后继(即出度为0)的顶点。对于一个DAG,按此方法输出的序列是逆拓扑次序。
仍然可以利用数组模拟的方法存放之后逆序输出;也可以用栈来存放,排序方法如上,入栈之后按顺序输出即可。
我是利用广搜和深搜实现拓扑排序