拓扑排序(备忘自用)

拓扑排序

文章目录

  • 拓扑排序
    • 1.有向无环图
    • 2.拓扑排序
    • 3.CodeUp例题
    • 总结


1.有向无环图

一个无环的有向图称做有向无环图(Directed Acyclic Graph,DAG)。它是指一个有向图的任意顶点都无法通过一些有向边回到起点。
拓扑排序(备忘自用)_第1张图片

2.拓扑排序

拓扑排序是将有向无环图G的所有顶点排成一个线性序列,使得对图G中的任意两个顶点u,v,如果存在边u->v,那么在序列中u一定在v前面。这个序列被称为拓扑排序。

比如在实验室的诸葛老师让啥都不会的你设计一个逆变器!你只能先从C语言,电路开始,一步步向后最终完成设计逆变器的目标。

拓扑排序(备忘自用)_第2张图片

同时还可以发现,若各种技术之间的先导关系不是直接或间接的,那么学习的顺序可任意决定。于是可以把上面的要学习的技术或者课程排成一个学习的先后序列,使得序列满足先导顺序。
电力电子,狗都不学

根据上面的图,拓扑排序就不难理解了。简单来说,就是如果有先导的结点,就先访问先导结点;如果没有先导结点或已访问果先导结点,那么这些结点的顺序任意。对应到图中,这个过程可以抽象为以下步骤

  1. 定义一个队列Q,并把所有度为0的结点加入队列;
  2. 取队首结点,输出,然后删去所有从它出发的边,并令这些边到达的顶点的入度减一。如果某个顶点的入度减为0,则将其加入队列。
  3. 反复进行②操作,直到队列为空为止。如果队列结束时,入过对的结点数恰好为N,说明拓扑排序成功,图G为有向无环图,否则,拓扑排序失败,图G中有环。

可以使用邻接表实现拓扑排序。并增加一个数组记录结点的入度。拓扑排序的代码如下:

vector<int> G[MAXV];  
int n, inDegree[MAXV];  
//拓扑排序  
bool toplogicalSort()  
{
          
	int num = 0;//记录加入排序的顶点数  
    queue<int> q;  
    for (size_t i = 0; i <n; i++)  
    {
       
        if (inDegree[i] == 0)  
       {
       
           q.push(i);//将度为0的点入队  
       }  
   }  
   while (!q.empty())  
   {
       
		int u = q.front();//取出队首顶点  
        q.pop();  
        for (int i = 0; i < G[u].size; i++)  
        {
       
            int v = G[u][i];//后继结点v  
            inDegree[v]--;//度减一  
            if (inDegree[v] ==0)
            {
       
                q.push(v);  
            }  
       }  
       G[u].clear();  
       num++;  
   }  
   if (num == n) return true;  
   else return false;  
}    

拓扑排序的重要应用就是判断一个给定的图是否是有向无环图。正如上面的代码,如果函数返回真,则说明排序成功,图是有向无环图。否则,说明拓扑排序失败,给定的图中有环。

值得注意的是,如果要求有多个入度为0的顶点,选择编号最小的顶点,那么把queue改成priority_queue,并保持队首元素是优先队列中最小的元素即可。

3.CodeUp例题

原题 CodeUp新家 Problem B: 确定比赛名次.

Description

有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

Input

输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

Output

给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

Example

3 2
3 1
3 2
17 16
16 1
13 2
7 3
12 4
12 5
17 6
10 7
11 8
11 9
16 10
13 11
15 12
15 13
17 14
17 15
17 16
0 0

代码

#include 
#include 
#include 
using namespace std;
const int maxn=100005;
int ind[maxn];
vector<int > G[maxn];
void print_Topological_sort(int n)
{
     
	priority_queue<int,vector<int>,greater<int> > q;
	for(int i=1;i<=n;i++)
	{
     
		if(ind[i]==0){
     
			q.push(i);
		}
	}
	while(!q.empty())
	{
     
		int u=q.top();
		q.pop();
		cout<<u<<" ";
		for(int j=0;j<G[u].size();j++)
		{
     
			int v=G[u][j];
			ind[v]--;
			if(ind[v]==0)
			{
     
				q.push(v);
			}			
		}
		G[u].clear();
	}
	fill(ind,ind+n+1,0);
	for(int i=0;i<=n;i++) G[i].clear();
	cout<<endl;
} 
int main()
{
     
	int N,M,a,b;
	while(cin>>N>>M)
	{
     
		if(N==0||M==0) break;
		for(int i=0;i<M;i++)
		{
     
			cin>>a>>b;
			G[a].push_back(b);
			ind[b]++;
		}
		print_Topological_sort(N);
	}
	return 0;
}

总结

byebye~

你可能感兴趣的:(备忘笔记,数据结构)