拓扑排序:
拓扑排序是应用于有向无回路图(DAG)上的一种排序方式,对一个有向无回路进行拓扑排序后,所有的顶点形成一个序列,对所有边(u,v),满足u在v的前面。该序列说明了顶点表示的事件或 状态发生的整体顺序。
比较经典的是在工程活动上,某些工程完成后,另一些工程才能继续,此时可以以工程为顶点,工程间的依赖关系为边建立图,用拓扑排序来求得所有工程的合理执行顺序。
对一个DAG进行拓扑排序有两种方法,广度优先搜索和深度优先搜索。
这里介绍广度优先搜索,进行拓扑排序时,每次可以拿出的顶点一定是入度为0的点,即没有被指向的点,因为这样的点表示的事件没有依赖,在一个入度为0的点表示的事件执行完之后,它所指向的顶点所依赖的点就少了一个,所以我们可以先将所有入度为0的点加入一个队列中,然后依次将它们所指向的点的入度减1,再将入度变为0的点也依次加入队列中,这样最后就可以得到一个拓扑有序的序列。
本题中说符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前,需要用到优先队列,每次从队列中取的是最小的那个元素。
#include <iostream> #include <stdio.h> #include <string.h> #include <queue> using namespace std; const int maxn=510; int graph[maxn][maxn];//保存图 int degree[maxn];//保存入度 int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { memset(graph,0,sizeof(graph)); memset(degree,0,sizeof(degree)); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); if(!graph[u][v]) { graph[u][v]=1; degree[v]++;//v的入度++ } } priority_queue<int,vector<int>,greater<int> >q; for(int i=1;i<=n;i++) if(degree[i]==0) q.push(i); bool first=1; while(!q.empty()) { int cur=q.top(); q.pop(); if(first) { cout<<cur; first=0; } else cout<<" "<<cur; for(int i=1;i<=n;i++) { if(graph[cur][i]) { degree[i]--;//相连的点的入度减1 if(degree[i]==0)//如果入度为0,加入队列 q.push(i); } } } printf(" "); } return 0; }
/** * The Kahn's Topological Sort Algorithm in C++ * Using the Adjecency List * Time Cost : O(|V|+|E|) * Author: Zheng Chen / Arclabs001 * Copyright 2015 Xi'an University of Posts & Telecommunications */ #include <iostream> #include <queue> #include <vector> using namespace std; const int N = 5; // The number of Vertex enum status {UNDISCOVERED,VISITED}; struct Vertex { int inDegree, outDegree; int data; status _stat; }V[N]; vector<int> AdjList[N]; //Using vector to simulate the adjlist queue<int> vertexQueue; //The call queue /** * Initialize the graph as below: The Graph: 0->1->3 | | | / / / 2->4<-- * @return The pointer to the start vertex */ Vertex* init_graph() { while(!vertexQueue.empty()) vertexQueue.pop(); for(int i=0; i<N; i++) { AdjList[i].clear(); V[i]._stat = UNDISCOVERED; V[i].data = i; } V[0].inDegree = 0; V[0].outDegree = 2; V[1].inDegree = 1; V[1].outDegree = 3; V[2].inDegree = 1; V[2].outDegree = 1; V[3].inDegree = 1; V[3].outDegree = 1; V[4].inDegree = 3; V[4].outDegree = 0; AdjList[0].push_back(1); AdjList[0].push_back(2); AdjList[1].push_back(3); AdjList[1].push_back(4); AdjList[2].push_back(4); AdjList[3].push_back(4); return & V[0]; } bool Topological_Sort() { for(int i=0; i<N; i++) { if(V[i].inDegree == 0) vertexQueue.push(i); } while(!vertexQueue.empty()) { int top = vertexQueue.front(); V[top].outDegree = 0; V[top]._stat = VISITED; int i=0; for(int v : AdjList[top]) { --V[v].inDegree; AdjList[top][i++] = -1; if(V[v].inDegree == 0) vertexQueue.push(v); } cout<<top<<" "; vertexQueue.pop(); } for(int i=0; i<N; i++) { for(int v : AdjList[i]) if(v != -1) { return false; } } return true; } int main() { init_graph(); bool status = Topological_Sort(); if(status == false) { cout<<"Error! The graph has at least one cycle!"<<endl; } return 0; }