[知识点]拓扑排序

// 此博文为迁移而来,写于2015年2月24日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vspe.html

1、前言

在了解拓扑排序之前,我们先来看一道题目以更好的理解:

一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动(activity)。在整个工程中,有些子工程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的结束为先决条件的,但有些子工程没有先决条件,可以安排在任何时间开始。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。

课程代号      课程名称        先修课程

C1          高等数学             无

C2          程序设计基础      无

C3          离散数学             C1,C2

C4          数据结构             C3,C5

C5          算法语言             C2

C6          编译技术             C4,C5

C7          操作系统             C4,C9

C8          普通物理             C1

C9          计算机原理         C8

其AOV网如图所示:

2、什么是拓扑排序?

一个AOV网应该是一个有向无环图,即不应该带有回路,因为若带有回路,则回路上的所有活动都无法进行。一个具有三个顶点的回路,由边可得B活动必须在A活动之后,由边可得C活动必须在B活动之后,所以推出C活动必然在A活动之后,但由边可得C活动必须在A活动之前,从而出现矛盾,使每一项活动都无法进行。这种情况若在程序中出现,则称为死锁或死循环,是应该必须避免的。

在AOV网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order),由AOV网构造拓扑序列的过程叫做拓扑排序(Topological sort)。AOV网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。例如,下面的三个序列都是上图的拓扑序列,当然还可以写出许多。

(1) C1,C8,C9,C2,C3,C5,C4,C7,C6

(2) C2,C1,C3,C5,C4,C6,C8,C9,C7

(3) C1,C2,C3,C8,C9,C5,C4,C6,C7

3、有什么作用?

除了上面我们之前我们展示的一道题目,拓扑排序的应用是比较广泛的。下面我们再看一个例子:

士兵排队 Soldier.cpp

<1>问题描述

有N名士兵(1<=N<=26),编号依次为A,B,C,……进行队列训练时,指挥官要把一些士兵从高到矮依次排成一行,但现在指挥官不能直接获得每个士兵的身高信息,只能获得“P1比P2高”这样的比较结果(P1,P2∈{A,B,…Z},记为P1>P2),如“A>B”表示A比B高。编一程序,根据所得到的比较结果求出符合条件的排队方案。注:比较结果中没有涉及到的士兵不参加排队。

例如,设有3个士兵,A、B、C,给出关系(A,B),(B,C)。其中(A,B)表示士兵A高于B,当上面的关系给出之后,可以将他们排成一队:ABC。

<2>输入

通过文件输入,每个比较结果在文件中占一行。

<3>输出

若输入数据无解或不能唯一确定,则输出“NO  ANSWER!”,否则从高到矮依次输出每一个士兵的编号,中间无分隔符,并把结果写入文本文件中。

<4>输入样例

A>B

B>F

F>D

<5>输出样例

ABFD

代码如下:

#include<cstdio>

#include<cstdlib>

#define MAXN 28

struct edge

{

  int next,v;

};

edge list[MAXN*2];

int head[MAXN],tot,n,have[MAXN],ListNum[MAXN],del[MAXN],get,ans[MAXN];

void AddList(char strU,char strV)

{

  int u=strU-64,v=strV-64;

  have[u]=have[v]=1;

  tot++;

  list[tot].v=v;

  list[tot].next=head[u];

  head[u]=tot;

  ListNum[v]++;

}

void init()

{

  char s[4];

  freopen("3.in","r",stdin);

  freopen("3.out","w",stdout);

  while (scanf("%s",s)!=EOF) AddList(s[0],s[2]);

  for (int i=1;i<=26;i++)

    if (have[i]==1) n++;

}

int check()

{

  for (int i=1;i<=26;i++)

    if (del[i]!=1 && have[i]==1) return 0;

  return 1;

}

void DFS(int now,int dep)

{

  del[now]=1;

  for (int x=head[now];x!=0;x=list[x].next)

    ListNum[list[x].v]--;

  ans[dep]=now;

  if (check()==1)

  {

    if (get==1) { printf("NO ANSWER!"); exit(0); }

    else { get=1; return; }

  }

  for (int i=1;i<=26;i++)

    if (ListNum[i]==0 && del[i]!=1 && have[i]==1) DFS(i,dep+1);

  for (int x=head[now];x!=0;x=list[x].next)

    ListNum[list[x].v]++;

  del[now]=0;

}

int main()

{

  init();

  for (int i=1;i<=26;i++)

    if (ListNum[i]==0 && have[i]==1) DFS(i,1);

  if (get==0) printf("NO ANSWER!");

  else for (int i=1;i<=n;i++) printf("%c",ans[i]+64);

  return 0;

}

时间: 2024-10-14 10:32:48

[知识点]拓扑排序的相关文章

拓扑排序的 +Leapms 线性规划模型

知识点 拓扑排序 拓扑排序的+Leapms模型 无圈有向图 一个图G(V,E), 如果边有向且不存在回路,则为无圈有向图.在无圈有向图上可以定义拓扑排序.下图是一个无圈有向图的例子. 拓扑排序 给定一个无圈有向图G(V,E),对其顶点集合V中的元素进行排序,使得对任何两个顶点v1,v2,如果(v1,v2)是图上的一条边,则在排序中v1优先于v2. 拓扑排序的+Leapms模型 对图G(V,E)中的边的表示可以用其起始边和终止边表示,对第k条边,其起始定点使用函数alpha[k]表示,其终止顶点用

图论-拓扑排序详解

拓扑排序(topsort)详解 这篇随笔就信息学奥林匹克竞赛中图论的一个知识点--拓扑排序进行讲解.拓扑排序的内容比较基础,只要求读者学习过并了解信息学中图的相关定义和一些专业名词,但是拓扑排序的变形题目比较多,希望读者在看完本随笔后认真体会练习,掌握拓扑排序. 上课! 拓扑排序的定义 顾名思义,这是一种排序,确切地说,是一种图上排序,在一张有向无环图(注解:有向无环图即很多参考书和题解中所说的DAG)上进行排序,把其中的所有节点排成一个序列,使得图中的任意一对有边相连的节点(u,v)u要出现在

UVa 872 - Ordering 输出全拓扑排序

本题要求输出全部拓扑排序的序列. 还好本题的数据量不是很大,限制在26个大写英文字母,故此可以使用递归法输出. 这个递归输出全部解在Leetcode很多这样的题目的,不小心的话,还是很难调试的. 总体考了递归和拓扑排序,还有判断是否可以拓扑排序-就是是否图有环. 考了三大知识点,难度还是有的.因为数据量不大,故此判断环可以使用一般递归方法,递归只需要注意细节就好了. #include <stdio.h> #include <vector> #include <string.h

hdu1811 Rank of Tetris(拓扑排序+并查集)

Rank of Tetris Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6920    Accepted Submission(s): 1947 Problem Description 自从Lele开发了Rating系统,他的Tetris事业更是如虎添翼,不久他遍把这个游戏推向了全球. 为了更好的符合那些爱好者的喜好,Lele又想

拓扑排序讲解

在这里我们要说的拓扑排序是有前提的 我们在这里说的拓扑排序是基于有向无环图的!!!. (⊙o⊙)…我所说的有向无环图都知道是什么东西吧.. 如果不知道,我们下面先来来说说什么是有向无环图. 所谓有向无环图,顾名思义是不存在环的有向图(至于有向图是什么不知道的在前面我们有一个图论讲解上都有). 点的入度:以这个点为结束点的边数. 点的出度:以这个点为出发点的边的条数. 拓扑序就是对于一个节点的一个排列,使得(u,v)属于E,那么u一定出现在v的前面.然而拓扑排序就是一个用来求拓扑序的东西. 对于左

CSU 1804: 有向无环图(拓扑排序)

http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1804 题意:…… 思路:对于某条路径,在遍历到某个点的时候,之前遍历过的点都可以到达它,因此在这个时候对答案的贡献就是∑(a1 + a2 + a3 + ... + ai) * bv,其中a是之前遍历到的点,v是当前遍历的点. 这样想之后就很简单了.类似于前缀和,每次遍历到一个v点,就把a[u]加给a[v],然后像平时的拓扑排序做就行了. 1 #include <bits/stdc++.h>

7-9-有向图无环拓扑排序-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第7章  图 - 有向无环图拓扑排序 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.SequenceStack.c.ALGraph.c    

hihoCoder 1175:拓扑排序二

题目链接: http://hihocoder.com/problemset/problem/1175 题目难度:一星级(简单题) 今天闲来无事,决定刷一道水题.结果发现这道水题居然把我卡了将近一个钟头. 最后终于调通了.总结起来,原因只有一个:不够仔细. 思路不用细说了,就是拓扑排序的简单应用.然而,一些不起眼的细节才是让你掉坑里的真正原因. 猜猜哪儿可能出bug? // A simple problem, but you can't be too careful with it. #inclu

hdu1285(拓扑排序)

这道题要求没有输赢关系的两个元素必须按照升序输出,有输赢关系的,赢得在输的前面,所以用队列或者栈来降低时间复杂度的优化过的拓扑排序会出错. 比如这组输入 5 3 1 2 2 3 4 5 至少我写的两种拓扑排序都wa了.但是不用队列或者栈来优化的话, 1.每次都从头至尾扫描一遍,找到一个没标记过的节点, 2.将它标记 3.然后删除从它出来的每条边. 重复这三个操作,加标记的次序,就是题目要的答案. 下面的代码中用到了队列,但只是用来保存答案而已.并没有用它优化的意思. #include <iost