算法学习 拓扑排序(TopSort)
拓扑排序
一、基本概念
在一个有向无环图(Directed Acyclic Graph, DAG)中,规定< u,v > 表示一条由u指向v的的有向边。要求对所有的节点排序,使得每一条有向边 < u,v>中u都排在v的前面。
换个形象点的解释,我们在学习一门课程之前,应该需要一定的预备知识,比如在学习B课程之前我们需先学习A(后用< X,Y > 表示X课程是Y课程的预备知识,其实与上述有序偶的含义相同),则有 < A,B >。我们还有 < C,B >, < B,D >, < E,D >, < D,F >, < D,G >, < H,G >. 现在要求你合理安排A-H这些课程的学习顺序。这个任务的要求实际上就是对A-H进行拓扑排序。
为何要求这个图是DAG呢?不难想象,如果上面的课程变成 < A,B >, < B,C >, < C,D > …… < H,A >. (即A-H成有向环)那么我们就无法判断出先学哪个课程了。
二、算法实现
以上面给课程排序为例,我们首先要学的,一定是一个不需要任何预备知识的课程,然后学完这个课程之后,根据边的关系再看有哪些新的课程可以学习,同时我们还要清楚,学完一门课程后,就不需要再次学习这一门课程了。
我们将其与图做个类比。
不需要预备知识的课程-> 入度为0的点
新的课程->所指向的下一个点
每门课之学一次->从图中删除节点 && 从图中删除有向边
接着再根据图类比结果决定存储的数据
入度为0的点->需要存储每个节点的入度
所指向的下一个点->需要存每个节点的后继
删除节点与有向边-> 这里讨论一下:
如果我们真的删除了节点和有向边,那就意味着无法在找到这些数据了。因为我们还需要判断是否形成了DAG,最保险的做法是将下一个节点的入度-1。如果发现某个节点的入度为-1了,表明存在有向环,那么说明不存在与拓扑排序。
根据存储的数据选择数据结构(具体情况具体分析,灵活变通)
节点入度->数组
节点后继->vector
三、例题讲解
UVA.10305 Ordering Tasks
有n个点,m条边,给n个顶点做拓扑排序。
#include <iostream>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <sstream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#define nmax 200
#define MEM(x) memset(x,0,sizeof(x))
using namespace std;
vector<int> v[nmax];
int indegree[nmax];
int n;
bool suc = true;
queue<int> ans;
void topsort()
{
queue<int> q;
while(1){
for(int i = 1; i<=n ;++i){
if(indegree[i] == 0){
q.push(i);
ans.push(i);
indegree[i] = -1;
}
}
if(q.empty()) break;
while(!q.empty()){
int t = q.front(); q.pop();
for(int j = 0;j<v[t].size();++j){
int tt = v[t][j];
if(indegree[tt] == -1){
suc = false;
break;
}else indegree[tt]--;
}
v[t].clear();
if(!suc) break;
}
if(!suc) break;
}
if(ans.size() <n){
suc =false;
return;
}
}
void output()
{
bool isfirst = true;
while(!ans.empty()){
int t = ans.front(); ans.pop();
if(isfirst){
printf("%d",t);
isfirst = false;
}else
printf(" %d",t);
}
printf("\n");
}
int main()
{
//freopen("in.txt","r",stdin);
int m;
while(scanf("%d%d",&n,&m) ==2 && (n||m)){
MEM(indegree);
suc = true;
int a,b;
for(int i = 0; i<m; ++i){
scanf("%d%d",&a,&b);
indegree[b]++;
v[a].push_back(b);
}
topsort();
if(suc) output();
else printf("failed\n");
}
return 0;
}
基本方法是,indegree表示入度表,vector存后继节点。在topsort函数中,制造一个辅助队列,首先从入度表中找到入度为0的点作起点,并且置入度为-1。接着依次处理队列中的节点,首先根据他们的后继,将其后继节点的入度依次减1,若其后继节点中的入度存在-1的,说明成环,则不存在拓扑排序。紧接着再从入度表中找到入度为0的节点,加入到队列中,直到队列空。当退出while循环的时候,需要检查ans答案队列中是否已经有全部的节点,若其数量为n,则表明存在拓补排序,否则不存在。
当然本题满足存在topsort。下面给出三组例子,可以检验一下自己程序的健壮性。
Graph1
不存在拓扑排序,节点2,3,4成环
4 5
1 3
1 2
2 3
3 4
4 2
Graph2
不存在拓扑排序,节点1,2,3成环
5 6
5 1
1 2
2 3
3 1
1 4
4 3
Graph3
存在拓扑排序
13 14
1 2
1 6
1 7
3 1
3 4
4 6
6 5
8 7
9 8
7 10
10 11
10 12
10 13
12 13
算法学习 拓扑排序(TopSort)的更多相关文章
- HDU.3342 Legal or Not (拓扑排序 TopSort)
HDU.3342 Legal or Not (拓扑排序 TopSort) 题意分析 裸的拓扑排序 根据是否成环来判断是否合法 详解请移步 算法学习 拓扑排序(TopSort) 代码总览 #includ ...
- HDU.2647 Reward(拓扑排序 TopSort)
HDU.2647 Reward(拓扑排序 TopSort) 题意分析 裸的拓扑排序 详解请移步 算法学习 拓扑排序(TopSort) 这道题有一点变化是要求计算最后的金钱数.最少金钱值是888,最少的 ...
- HDU.1285 确定比赛名次 (拓扑排序 TopSort)
HDU.1285 确定比赛名次 (拓扑排序 TopSort) 题意分析 裸的拓扑排序 详解请移步 算法学习 拓扑排序(TopSort) 只不过这道的额外要求是,输出字典序最小的那组解.那么解决方案就是 ...
- 拓扑排序 topsort详解
1.定义 对一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列,通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列. 举例: h3 { marg ...
- NetworkX系列教程(10)-算法之四:拓扑排序与最大流问题
小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...
- 拓扑排序 topsort
拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序 ...
- 算法学习记录-排序——插入排序(Insertion Sort)
插入排序: 在<算法导论>中是这样描述的 这是一个对少量元素进行排序的有效算法.插入排序的工作机理与打牌时候,整理手中的牌做法差不多. 在开始摸牌时,我们的左手是空的,牌面朝下放在桌子上. ...
- 算法学习记录-排序——冒泡排序(Bubble Sort)
冒泡排序应该是最常用的排序方法,我接触的第一个排序算法就是冒泡,老师也经常那这个做例子. 冒泡排序是一种交换排序, 基本思想: 通过两两比较相邻的记录,若反序则交换,知道没有反序的记录为止. 例子: ...
- 【算法学习记录-排序题】【PAT A1012】The Best Rank
To evaluate the performance of our first year CS majored students, we consider their grades of three ...
随机推荐
- ThinkPHP开启设置子域名笔记
一.ThinkPHP框架里 common下的config文件 'APP_SUB_DOMAIN_DEPLOY' => 1, // 开启子域名配置 'APP_SUB_DOMAIN_RULES' =& ...
- 金山WPS面试题
1.windows的handle 1)是一个宏定义#define void* HANDLE 2) HANDLE提供了一种统一的方式去获得系统资源,并对其进行操作. 3) HANDLE使得程序设计的细节 ...
- 「日常训练」Uncle Tom's Inherited Land*(HDU-1507)
题意与分析 题意是这样的:给你一个\(N\times M\)的图,其中有一些点不能放置\(1\times 2\)大小的矩形,矩形可以横着放可以竖着放,问剩下的格子中,最多能够放多少个矩形. 注意到是\ ...
- 创建并运行第一个Django项目
首先, 添加Django模块: 在CMD命令行输入 python -m django --version 查看Django版本: 创建第一个Django项目: 整个工程的目录结构: mysite目录是 ...
- JMeter自学笔记2-图形界面介绍
一.写在前面的话: 上篇我们已经学会了如何安装JMeter和打开JMeter,那么这篇我们将对JMeter的图形界面做一个简单的介绍.大家只要简单的了解即可,无需死记硬背,在今后的学习和使用中慢慢熟悉 ...
- Linux命令应用大词典-第 15章 文件、目录权限和属性
15.1 chmod:更改文件和目录的模式 15.2 chown:更改文件和目录的用户所有者和组群所有者 15.3 chgrp:更改文件或目录的所属组 15.4 umask:显示和设置文件及目录创建默 ...
- 第三模块:面向对象&网络编程基础 第2章 网络编程
01-计算机基础 02-什么是网络 03-五层协议详解 04-传输层详解 05-什么是Socket 06-基于socket实现简单套接字通信 07-在简单套接字基础上加上通信循环 08-客户端与服务端 ...
- 安装mysql-5.7.12-winx64
之前安装mysql时未做总结,换新电脑,补上安装记录,安装的时候,找了些网友的安装记录,发现好多坑 1.mysql-5.7.12-winx64.zip下载 官方下载地址:http://dev.mysq ...
- Java Swing学习笔记——创建JFrame
创建显示一个空JFrame import javax.swing.JFrame; public class JFrameDemo extends JFrame{ public JFrameDemo() ...
- CodeForces - 776C(前缀和+思维)
链接:CodeForces - 776C 题意:给出数组 a[n] ,问有多少个区间和等于 k^x(x >= 0). 题解:求前缀和,标记每个和的个数.对每一个数都遍历到1e5,记录到答案. # ...