首页 > 其他分享 >拓扑排序

拓扑排序

时间:2023-04-03 19:14:03浏览次数:56  
标签:ch int text 拓扑 入队 排序

拓扑排序

前言

拓扑排序是一种图论算法,拓扑图被简称为 \(\text{DAG}\)(有向无环图)。

下面来说说拓扑序的定义吧:对于一个有向图 \(G\),拓扑序是关于这个图的一个线性序列,这个序列满足当 \(<u,v> \in G\) 且 \(u \to v\) 时,\(u\) 在 \(v\) 的前面。这里解释的可能比较浅显,详情请查阅百度百科

算法讲解

例题 AcWing 1191. 家谱树

一般的拓扑排序分为这几步:

  1. 统计每个点的入度,入度为 \(0\) 的点入队;
  2. 将队头拿出,遍历其所能到达的点 \(j\),将 \(d_j - 1\),如果 \(d_j = 0\),入队;
  3. 重复 2.,直到跑完整个图;

这是一个算是比较简单的算法了 此题是裸的 \(\text{topsort}\),代码放在下面了。

AC Code of AcWing 1191. 家谱树

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int N = 110;

int n,m,d[N],q[N];
int h[N],e[N << 1],ne[N << 1],idx;

inline int read() {
	int x = 0,f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + ch - 48;
		ch = getchar();
	}
	return x * f;
}

inline void add(int a,int b) {
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx ++;
}

inline void topsort() {
	int hh = 0,tt = -1;
	for (int i = 1; i <= n; ++ i ) 
	    if (!d[i]) 
	        q[++ tt] = i;
	while (hh <= tt) {
		int t = q[hh ++];
		for (int i = h[t]; ~i; i = ne[i] ) {
			int j = e[i];
			-- d[j];
			if (!d[j]) q[++ tt] = j;
		}
	}
}

signed main() {
	memset(h,-1,sizeof h);
	n = read();
	for (int i = 1; i <= n; ++ i ) {
		int a;
		while (cin >> a && a) add(i,a),++ d[a];
	}
	topsort();
	for (int i = 0; i < n; i ++ ) cout << q[i] << " ";
	return 0;
}

这里我是用的手写队列,当然你可以用 \(\text{STL}\)。

练习

接下来谈几道比较经典的题目。

  1. P1983 [NOIP2013 普及组] 车站分级 ,这道题就是跑一遍拓扑排序,然后求个最短路就好,代码就不放了。

  2. P3243 [HNOI2015]菜肴制作 ,此题强烈推荐做一做,做后会有比较大的收获。同样是先跑,然后在跑的时候求要求的值就好。

\[\text{Thanks} \]

作者:\(\text{songszh}\)

标签:ch,int,text,拓扑,入队,排序
From: https://www.cnblogs.com/songszh/p/top-sort.html

相关文章

  • C# Nuget版本号排序
    Nuget包版本号和我们软件应用版本号一样,不过因为稳定性等的考虑,组件版本有更高的要求。预发布版本使用频率更高版本号介绍,详见我朋友胡承老司机的博客:Nuget包的版本规范(qq.com)比如1.0.1-alpha.2,表示1.0.1有个开发联调版本alpha,alpha版本下面有构建号次数2。也有开发在构建号......
  • 对list中的字段进行自定义排序,最后放在LinkedHashMap中
    List<ProjectVO>projectList=dbProjectService.getProjectList();这里面如果第一个字段是如下的顺序:"成都分公司","北京分公司","上海分公司","深圳分公司","广州分公司","重庆分公司"Map<String,List<ProjectVO>>map=projectL......
  • MySQL实现over partition by(分组后对组内数据排序)
     开发中遇到了这样一个需求:统计商品库存,产品ID+子产品名称都相同时,可以确定是同一款商品。当商品来自不同的渠道时,我们要统计每个渠道中最大的那一个。如果在Oracle中可以通过分析函数OVER(PARTITIONBY…ORDERBY…)来实现。在MySQL中应该怎么来实现呢。现在通过两种......
  • 冒泡排序算法(超级详细)
    泡排序是一种简单的排序算法,它也是一种稳定排序算法。其实现原理是重复扫描待排序序列,并比较每一对相邻的元素,当该对元素顺序不正确时进行交换。一直重复这个过程,直到没有任何两个相邻元素可以交换,就表明完成了排序。一般情况下,称某个排序算法稳定,指的是当待排序序列中有相同的......
  • js数组详解(四):排序API
    1.排序:   自定义排序:冒泡  排序API:arr.sort();    大问题:默认将所有元素转为字符串再按字符串排列         只能对字符串类型的元素正确排序    解决:自定义比较规则:      比较器函数:专门比较任意两值大小的......
  • 归并排序-小记
    归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(DivideandConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。类比题目:三数求和。......
  • 常见的几种排序
    1.冒泡排序$tarr=[4,2,3,1,5,0];functionsort_arr($arr){for($i=0;$i<count($arr);$i++){for($j=$i+1;$j<count($arr);$j++){if($arr[$i]>$arr[$j]){$temp=$arr[$i];$arr[$i]=$arr[$......
  • 分治(Divide and Conquer)算法之归并排序
    顾名思义,分治问题由“分”(divide)和“治”(conquer)两部分组成,通过把原问题分为子问题,再将子问题进行处理合并,从而实现对原问题的求解。我们在排序章节展示的归并排序就是典型的分治问题,其中“分”即为把大数组平均分成两个小数组,通过递归实现,最终我们会得到多个长度为1的子数组;“......
  • 寒假每日一题——困牛排序(思维题)
    困牛排序问题描述FarmerJohn正在尝试将他的N头奶牛,方便起见编号为1…N,在她们前往牧草地吃早餐之前排好顺序。当前,这些奶牛以p1,p2,p3,…,pN的顺序排成一行,FarmerJohn站在奶牛p1前面。他想要重新排列这些奶牛,使得她们的顺序变为1,2,3,…,N,奶牛1在FarmerJohn旁......
  • 快速排序及其优化
    packageleetcode.mySort;importjava.util.Random;publicclassQuickSort{privatefinalstaticRandomrandom=newRandom(System.currentTimeMillis());//快速排序的不同类型的写法,差别在于partition下面的partition是大学时候老师教的方法partition2是//......