我最痛恨的拓扑排序QwQ

鬼 知 道 刚 学 这 破 玩 意 的 时 候 我 有 多 绝 望,现在再回来学,嗯! 真 可 爱 

基本定义

拓扑序有以下几个特点

  • 拓扑序中的点没有指向它前面点的边(拓扑序中我们讨论的边均为有向边)
  • 由上一条可得拓扑序中若A指向B,则A一定排在B的前面
  • 要讨论拓扑序则该图中不得有环
  • 每个顶点在一个拓扑序中只出现一次
  • 一个图的正确拓扑序不止有一种

算法思想

每个点都有入度和出度,当某点入度为0时,则没有指向它的边,由拓扑序的第二条特点得出,这时没有点必须排在它的前面,于是将它加入拓扑序,就相当于在原图中删掉这个点,该点指向的所有点入度减一,重复此过程,直到所有点都加入了拓扑序

手动模拟

我最痛恨的拓扑排序QwQ_第1张图片

(图源见水印)

敲完算法思想之后我自己都晕咳咳咳,我们来手动模拟一下上面那个图(我 最 喜 欢 手 动 模 拟 数 据 了 !

初始图就是(a),图中入度为0的点是 1,6,所以1,6入队,这时的队(拓扑序)为{6,1}(顺序无所谓,我是为了配合图)

从队首开始,删掉队首点,将队首连出的边都删掉,相连的点入度-1,于是就得到了(b),6出队,此时的队列为{1}

重复上一步,最后得到出队的顺序就是拓扑序

 

算法实现

我在我平时用的几个oj上,我实在是没找到纯裸题QwQ,就直接自己敲了一个裸代码

#include
using namespace std;
int rd[10100],cd[10100],n,m,p[10100][10100],q[1010];
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		rd[b]++;//点b的入度++ 
		cd[a]++;//点a的出度++ 
		p[a][cd[a]]=b;//从点a出发的第cd[a]点是b 
	}
	int l=1;
	int r=0;//队列的左右端点 
	for (int i=1;i<=n;i++)
		if (rd[i]==0)
		{
			r++;
			q[r]=i;
		}//如果点i的入度为0,那么就把r入队,队列右端点++ 
	int cnt=n;
	while (cnt!=0)//当所有点都输出了之后,循环结束 
	{
		for (int j=1;j<=cd[q[l]];j++)
		{
			rd[p[q[l]][j]]--;
			if (rd[p[q[l]][j]]==0)
			{
				r++;
				q[r]=p[q[l]][j];
			}
		}
		printf("%d ",q[l]);
		cnt--;
		l++;
	}
	return 0;
}

洛谷1983 车站分级的传送门 呼——这道题比较裸,可以练手用

 

好啦好啦写完啦【完结撒花✿✿ヽ(°▽°)ノ✿】

 

【蒟蒻wyf要把学过的所有算法都写成博客!】

 

你可能感兴趣的:(算法)