zoukankan      html  css  js  c++  java
  • [旧版][知识点]拓扑排序

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

     

    Update - 20200607

    该博文内容现已更新并迁移至:

    [知识点] 8.4 拓扑排序与关键路径 https://www.cnblogs.com/jinkun113/p/13057781.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;
    }

     

  • 相关阅读:
    HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
    HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
    POJ 3974 Palindrome【manacher】【模板题】【模板】
    POJ 3974 Palindrome【manacher】【模板题】【模板】
    HDU 6127 Hard challenge【计算机几何】【思维题】
    HDU 6127 Hard challenge【计算机几何】【思维题】
    HDU 6129 Just do it【杨辉三角】【思维题】【好题】
    HDU 6129 Just do it【杨辉三角】【思维题】【好题】
    HDU 3037 Saving Beans【Lucas定理】【模板题】【模板】【组合数取余】
    8.Math 对象
  • 原文地址:https://www.cnblogs.com/jinkun113/p/4677200.html
Copyright © 2011-2022 走看看