基本概念:
一个有向无环图的拓扑序列是将图中的顶点排成一个线性序列,使得对于图中任意一对顶点u和v。若图中存在边<u,v>,则线性序列中
u在v之前出现。
(一)Khan算法:
①: 若图中剩余的点的入度均大于0则该图不存在拓扑序列,否则进行步骤②;
②: 取一个入度为0的顶点u并放置序列末尾;
③: 删除点u及点u伸出的所有边,同时与点u相连的点入度减1;
④: 若图中还存在顶点,再进行步骤①。
代码实现:
#define N 10005
bool vis[N];
int head[N], degree[N];
int Q[N], cnt, num;
struct EdgeNode{
int to;
int next;
};
EdgeNode edge[N];
//计算入度与出度
void add(int u, int v)
{
degree[v]++;
edge[cnt].to++;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void Topsort(int n)
{
num = 0;
for(int i = 1; i <= n; i++){
if(!degree[i] && vis[i]) //先将没有前驱的结点加入队列
Q[num++] = i;
for(int i = 0; i < num; i++){
//删除从该结点出发的所有边,更新degree数组
for(int k = head[Q[i]]; k != -1; k = edge[k].next){
degree[edge[k].to]--;
//如果degree数组为0,说明新的没有前驱的结点找到 ,加入队列中
if(!degree[edge[k].to])
Q[num++] = edge[k].to;
}
}
}
}
(二)基于DFS算法:代码实现:
1.
int timef = 0;
int n ;
int a[1000][1000];// 图的邻接矩阵
int f[1000]; //完成时间
int vis[1000]; //1代表 被发现 2代表 已完成
void DFS(int u)
{
vis[u] = 1; //记录发现时刻
for(int v=1; v<=n; v++){ //adj(u) //O(E)
if(a[u][v] && vis[v]==0)
DFS(v);
}
Vis[u] = 2; //记录完成时刻
timef++;
f[u] = timef;
}
void DFS_main() //O(V+E)
{
timef = 0;
for(int i=1; i<=n; i++){ // O(V)
if(vis[i] == 0)
DFS(i);
}
}
void Topological_sort() //O(V+E)
{
int tp[1000]; //存放拓扑序列1..V
DFS_main();
for(int i=1; i<=n; i++) //按finish的时间倒序存放在tp序列tp中
tp[n-f[i]+1] = i;
for(int i=1; i<=n; i++)
cout<<tp[i]<<" ";
cout<<endl;
}
2.
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100 //最大顶点个数
int n, m; //顶点数,边数
struct arcnode //边结点
{
int vertex; //与表头结点相邻的顶点编号
arcnode * next; //指向下一相邻接点
arcnode() {}
arcnode(int v):vertex(v),next(NULL) {}
};
struct vernode //顶点结点,为每一条邻接表的表头结点
{
int vex; //当前定点编号
arcnode * firarc; //与该顶点相连的第一个顶点组成的边
}Ver[maxn];
void Init() //建立图的邻接表需要先初始化,建立顶点结点
{
for(int i = 1; i <= n; i++)
{
Ver[i].vex = i;
Ver[i].firarc = NULL;
}
}
void Insert(int a, int b) //插入以a为起点,b为终点,无权的边
{
arcnode * q = new arcnode(b);
if(Ver[a].firarc == NULL)
Ver[a].firarc = q;
else
{
arcnode * p = Ver[a].firarc;
while(p->next != NULL)
p = p->next;
p->next = q;
}
}
#define INF 9999
bool visited[maxn]; //标记顶点是否被考察,初始值为false
int parent[maxn]; //parent[]记录某结点的父亲结点,生成树,初始化为-1
int d[maxn], time, f[maxn]; //时间time初始化为0,d[]记录第一次被发现时,f[]记录结束检查时
int topoSort[maxn];
int cnt;
void dfs(int s) //深度优先搜索(邻接表实现),记录时间戳,寻找最短路径
{
//cout << s << " ";
visited[s] = true;
time++;
d[s] = time;
arcnode * p = Ver[s].firarc;
while(p != NULL)
{
if(!visited[p->vertex])
{
parent[p->vertex] = s;
dfs(p->vertex);
}
p = p->next;
}
time++;
f[s] = time;
topoSort[cnt++] = s; //DFS拓扑序列逆序存放在topoSort[ ]中,因为先被保存的一定是搜索树叶子节点
}
void dfs_travel() //遍历所有顶点,找出所有深度优先生成树,组成森林
{
for(int i = 1; i <= n; i++) //初始化
{
parent[i] = -1;
visited[i] = false;
}
time = 0;
for(int i = 1; i <= n; i++) //遍历
if(!visited[i])
dfs(i);
//cout << endl;
}
void topological_Sort()
{
cnt = 0;
dfs_travel();
for(int i = cnt-1; i >= 0; i--)
cout << topoSort[i] << " ";
cout << endl;
}
int main()
{
int a, b, w;
cout << "Enter n and m:";
cin >> n >> m;
Init();
while(m--)
{
cin >> a >> b; //输入起点、终点
Insert(a, b); //插入操作
}
topological_Sort();
return 0;
}
例题:HDU--4857
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define maxn 30005
using namespace std;
int n,m;
bool vis[maxn];
int in[maxn];
vector<int> edge[maxn];
priority_queue<int> q;
void topsort(int n)
{
for(int i = 1; i <= n; i++){
if(in[i]==0)
q.push(i);
}
int ans = 0;
vector<int> res;
int u, v;
while(!q.empty()){
ans++;
u = q.top();
res.push_back(u);
q.pop();
vis[u]=1;
for(int i = 0; i<edge[u].size(); i++){
v = edge[u][i];
in[v]--;
if(in[v] == 0)
q.push(v);
}
}
for(int i = res.size()-1; i >= 0; i--){
if(i == res.size()-1)
printf("%d",res[i]);
else
printf(" %d",res[i]);
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d %d",&n,&m);
memset(in, 0, sizeof(in));
for(int i = 1; i <= n; i++)
edge[i].clear();
int u,v;
while(m--){
scanf("%d %d",&u,&v);
in[u]++;
edge[v].push_back(u);
}
memset(vis, 0, sizeof(vis));
topsort(n);
puts("");
}
return 0;
}