算法学习 拓扑排序(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 ...
随机推荐
- Android 9 适配怎么做? “QQ音乐”优化实录
WeTest 导读 2018年8月7日,Google对外发布最新 Android 9.0 正式版系统,并宣布系统版本Android P 被正式命名为代号“Pie”,最新系统已经正式推送包括谷歌Pixe ...
- 怎样安装Appium
在浏览器地址栏输入 http://appium.io/ 打开Appium官网: 安装包下载完成后, 一路默认安装, 什么都不用点击, 等待大约10分钟: 安装完成后, 会在桌面生成快捷图标: 启动: ...
- Selenium 入门到精通系列:五
Selenium 入门到精通系列 PS:显式等待.隐式等待.强制等待方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...
- 用IDEA编写spark的WordCount
我习惯用Maven项目 所以用IDEA新建一个Maven项目 下面是pom文件 我粘上来吧 <?xml version="1.0" encoding="UTF-8& ...
- Objective-C 构造方法 分类 类的深入研究
构造方法 1.对象创建的原理 new的拆分两部曲 Person *p = [Person alloc]; 分配内存(+alloc) Person *p = [p init]; 初始化(-init) 合 ...
- Python爬虫模拟登录带验证码网站
问题分析: 1.爬取网站时经常会遇到需要登录的问题,这是就需要用到模拟登录的相关方法.python提供了强大的url库,想做到这个并不难.这里以登录学校教务系统为例,做一个简单的例子. 2.首先得明白 ...
- 深入理解java虚拟机学习笔记(一)
第二章 Java内存区域与内存溢出异常 运行时数据区域 程序计数器(Program Counter Register) 程序计数器:当前线程所执行的字节码行号指示器.各条线程之间计数器互不影响,独立存 ...
- Android开发-API指南-<uses-permission>
<uses-permission> 英文原文:http://developer.android.com/guide/topics/manifest/uses-permission-elem ...
- Y460蓝牙键盘无法连接问题解决
mac坏了,无法启动,一直没时间去修理. 近期把大学的时候用的笔记本又翻了出来,小Y,经典的“娱乐本” Y460. Y460上之前被自己各种重装系统,反复从windows到双系统,再到linux之间来 ...
- 【未完】训练赛20190304:KMP+树状数组+线段树+优先队列
头炸了啊,只做出L题,前两天刚看的Shawn zhou的博客学习的,幸亏看了啊,否则就爆零了,发现题目都是经典题,线段树,KMP,我都没看过,最近又在复习考研,真后悔大一大二没好好学习啊,得抽时间好好 ...