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

拓扑排序

时间:2024-08-20 11:05:35浏览次数:13  
标签:toposort din int 拓扑 tp 存点 排序

拓扑排序(所有点按照先后顺序排成序列)

  • 注:图必须是有向无环图

Kahn (卡恩) 算法

核心思想:用队列维护一个入度为0的节点的集合

具体代码如下:

vector<int> e[N], tp;
int din[N];

e[x] 用来存点 x 的邻点,tp 存拓扑序列,din[x] 用来存点x的入度

bool toposort() {
	queue<int> q;
	for(int i = 1; i <= n; i ++)
		if(!din[i]) q.push(i);  // 压入所有入度为0的点
	while(q.size()) {
		int x = q.front();
		q.pop();
		tp.push_back(x);
		for(auto y : e[x]) {
			if(--din[y] == 0) q.push(y);  // 将x的所有出边删除,若y的入度变为0,则将y入队
		}
	}
    return tp.size() == n;  // 如果最后tp中的元素不等于个数n,则说明有环
}

主函数操作:

int main() {
	cin >> n >> m;
	for(int i = 0; i < m; i ++) {
		cin >> a >> b;
		e[a].push_back(b);  // 压入a的邻点b
		din[b] ++;  // b的入度+1
	}
	if(!toposort()) cout << "-1" << endl;
	else {
		for(auto x : tp) {
			cout << x << " ";   // 遍历输出拓扑序
		}
	}
	return 0;
}

DFS算法

核心思想:染色法 每个点的颜色都会经历从 0 -> -1 -> 1 的染色过程

具体代码如下:

vector<int> e[N], tp;
int c[N]; // 染色数组

e[x] 用来存点 x 的邻点,tp 存拓扑序列,c[x] 存点 x 的颜色

bool dfs(int x) {
	c[x] = -1;  // -1 表示正在经历
	for(auto y : e[x]) {
		if(c[y] < 0) return 0;  // 为-1说明回到了祖先节点,有环退出
		else if(!c[y])  // 没走过继续走
			if(!dfs(y)) return 0;  // 有环退出
	}
	c[x] = 1;  // 1 表示已经完成
	tp.push_back(x);  // 完成的点加入tp数组
	return 1;
}

void toposort() {
	memset(c, 0, sizeof c);  // 先让每一个点都染色成0
	for(int i = 1; i <= n; i ++) {
		if(!c[i])  // 遍历每一个点,如果没走就dfs
			if(!dfs(i)) return ;  // 判断是否有环
	}
	reverse(tp.begin(), tp.end());  // dfs是从后往前记录的,所以需要反转下
}

重点

  • Kahn 算法是用队列维护, 顺着拓扑序收集点

  • DFS 算法是用系统栈维护, 逆着拓扑序收集点

  • 时间复杂度: \(O(E + V)\ 边数 + 点数\)

  • 不是连通也不影响拓扑排序

  • 若求字典序最小的拓扑排序,则将 Kahn 算法中的 队列 换成 优先队列(小根堆) 时间复杂度变为 \(O(E + VlogV)\)

点击查看代码
#include <bits/stdc++.h>

using namespace std;
const int N = 1e6 + 10;

int n, m, a, b;
vector<int> e[N], tp;
int din[N];

void toposort() {
	priority_queue<int, vector<int>, greater<int>> q;   // 小根堆
	for(int i = 1; i <= n; i ++)
		if(!din[i]) q.push(i);
	while(q.size()) {
		int x = q.top();
		q.pop();
		tp.push_back(x);
		for(auto y : e[x]) {
			if(--din[y] == 0) q.push(y);
		}
	}
}

int main() {
	cin >> n >> m;
	for(int i = 0; i < m; i ++) {
		cin >> a >> b;
		e[a].push_back(b);	// 压入a的邻点b
		din[b] ++;  // b的入度+1
	}
	toposort();
    for(auto x : tp) {
		cout << x << " ";	// 遍历输出拓扑序
    }
	return 0;
}

标签:toposort,din,int,拓扑,tp,存点,排序
From: https://www.cnblogs.com/yishujia/p/18368791

相关文章

  • STP(角色选举、状态、定时器、拓扑变更机制、PVST、PVST+增强特性)
    文章目录一、什么是STP定义特点工作原理专业术语二、STP角色选举1、配置命令:2、端口角色:三、STP的状态四、STP的定时器①HelloTime:2s②MaxAge:20s③ForwardDelay:15s④AgingTime:300s五、STP拓扑变化机制六、PVST七、PVST+增强特性......
  • 优化网络拓扑结构:策略、实践与技术
    摘要网络拓扑结构是网络设计的基础,它决定了网络的组织方式和数据流动的路径。优化网络拓扑结构对于提高网络性能、可靠性和可扩展性至关重要。本文将探讨网络拓扑结构的基本概念,分析影响网络性能的因素,并提出一系列优化策略和实践方法。1.网络拓扑结构概述网络拓扑结构......
  • C++图笔记(三)有向无环图(及最小生成树(略))以及剩下的排序
    目录一,定义:1,有向无环图 2,拓朴排序 1,每个顶点出现且仅仅出现一次。 2,若存在一条从顶点A到顶点B的路径,那么在序列中顶点A出现在顶点B的前面。二,DAG的性质性质1.  从任意一个起点进行dfs,必不会陷入死循环。性质2.  入度为0的点信息确定,删掉入度为0的点......
  • 排序算法 基数排序 RadixSort --C语言实现
    基数排序基数排序(radixsort)属于“分配式排序”(distributionsort),又称“桶子法”(bucketsort)或binsort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O(nlog(r)m),其中r为所采取的基数,而m为堆数......
  • el-table使用sortablejs推拽排序卡顿问题解决
    使用sortablejs拖拽el-table排序时,对于纯文本表格,正常使用即可,不会卡顿initSort(){consttbody=document.querySelector('.el-table__body-wrappertbody')const_this=thisSortable.create(tbody,{draggable:'.el-table__row',......
  • 常见的排序算法汇总(详解篇)
    目录排序的概念以及运用排序的概念1.插入排序1.1直接插入排序1.1.1 基本思想1.1.2代码实现直接插入排序的特征总结:1.1.3希尔排序(缩小增量排序)......
  • C语言学习--排序和查找
    提示:排序和查找算法是算法领域中最基本的概念之一,它们在数据组织、优化查询效率等方面发挥着至关重要的作用。目录前言12.1排序算法的介绍12.2冒泡排序12.2.1基本介绍12.2.2冒泡排序应用实例12.2.3分析冒泡的过程+代码12.3查找12.3.1介绍12.3.2案例演示12......
  • 2024百度之星决赛部分题解(难度排序前六题)
    前言手速6题,可惜第四题磨了几个小时没磨出来,多做一题就金了,还是实力差了点,最后银牌前列。下面的题解是根据代码回忆大概的题意,主要是给出来赛时的参考代码A.状压题意:学校集训队总的有\(n\)个人,保证\(n\)是3的倍数,每个人有个人实力\(a_i\),每两个人之间有配合程度\(b_{i......
  • 阿里云ACP的三种报名与对应题库获取方式的详细说明(按费用排序)
    文章目录前言方式一、官方途径(较为昂贵)考试资格获取官方视频教程获取方式总结方式二、报名机构(价格适中,考取速度快)推荐机构大概费用机构报名方式机构报名后所携带的内容或者说对于其他方法有什么优势总结方式三、闲鱼(最便宜,但题库有风险)考试资格获取题库获取总......
  • web前端之根据字符串长度从长到短排序、中文字符串优先、样式循环、禁止冒泡、悬浮、
    MENU前言效果图htmlstyleJavaScript前言1、代码段由HTML、CSS(使用Sass语法)和JavaScript组成,创建一个文本框,用户可以在其中输入内容,并通过点击按钮进行操作。2、代码段的主要功能是允许用户输入一系列以、分隔的项,并根据长度对这些项进行排序(中文字符优先),然后......