zoukankan      html  css  js  c++  java
  • AOV网络和Kahn算法拓扑排序

    1.AOV与DAG

    活动网络可以用来描述生产计划、施工过程、生产流程、程序流程等工程中各子工程的安排问题。

     
    一般一个工程可以分成若干个子工程,这些子工程称为活动(Activity)。完成了这些活动,整个工程就完成了。例如下图的代表的计算机专业课程,学习就是一个工程,每门课程的学习就是整个工程中的一个活动。图论——四、活动网络(AOV)网络
     
    我们可以用上图的有向图来表示课程之间的先修关系。在这种有向图中,顶点表示课程学习活动,有向边表示课程之间的先修关系。例如顶点C1到C8有一条有向边,表示课程C1必须在课程C8之前先学习完。
     
    实际上,在这种有向图中,用顶点表示活动,用有向边表示活动u必须先于活动v进行。这种有向图叫做活动网络(Activity on Vertices),记做AOV网络。
     
    前驱与后继:在AOV网络中,如果存在有向边,则称活动u必须在活动v之前进行,并称u是v的直接前驱,v是u的直接后继。如果存在有向路径,则称u是v的前驱,v是u的后继。
     
    有向环与有向无环图:从前驱与后继的传递性和反自反性可以看出,AOV网络中不能出现有向回路(或称为有向环)。不含有向回路的有向图称为有向无环图(DAG, Directed Acyclic Graph)。
     
    在AOV网络中如果出现了有向回路,则意味着某项活动以自己作为先决条件,这是不对的。
    2.拓扑排序
     
    判断有向无环图的方法是对AOV网络构造它的拓扑有序序列。即将各个顶点排列成一个线性有序的序列,使得AOV网络中所有存在的前驱和后继关系都能得到满足。
     
    这种构造AOV网络全部顶点的拓扑有序序列的运算称为拓扑排序(Topological Sorting)。
     
    如果通过拓扑排序能将AOV网络的所有顶点都排入一个拓扑有序的序列中,则该AOV网络中必定不存在有向环;相反,如果得不到所有顶点的拓扑有序序列,则说明该AOV网络中存在有向环,此AOV网络所代表的工程是不可行的。
     
    例如对上图所示的学生选课工程图进行拓扑排序,得到的拓扑有序序列为:
     
    C1,C2,C3,C4,C5,C6,C8,C9,C7
    或者
    C1,C8,C9,C2,C5,C3,C4,C7,C6 
     
    由此可见,AOV网络的拓扑有序序列可能不唯一。
     
    3.Kahn算法拓扑排序算法:
     
    (1)从有向图中选择一个没有前驱(即入度为0)的顶点并且输出它;
    (2)从网中删去该顶点,并且删去从该顶点发出的全部有向边;
    (3)重复上述两步,直到剩余的网中不再存在没有前趋的顶点为止。
     
    输入:
    6 8
    1 2
    1 4
    2 6
    3 2
    3 6
    5 1
    5 2
    5 6
    6 8
    1 3
    1 2
    2 5
    3 4
    4 2
    4 6
    5 4
    5 6
    输出:
    Great! There is not cycle.
    5 1 4 3 2 6
    Network has a cycle!
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #include<stack>
     8 #include<map>
     9 #include<set>
    10 #include<sstream>
    11 #include<functional>
    12 using namespace std;
    13 typedef long long ll;
    14 const int maxn = 1000 + 10;
    15 const int INF = 1e9 + 7;
    16 int T, n, m, cases;
    17 vector<int>Map[maxn];
    18 int Count[maxn];
    19 void topo()
    20 {
    21     stack<int>s;//存储入度数为0的顶点
    22     vector<int>v;//存取拓扑排序的答案
    23     for(int i = 1; i <= n; i++)//下标从1开始
    24         if(Count[i] == 0)s.push(i);
    25     while(!s.empty())
    26     {
    27         int now = s.top();
    28         v.push_back(now);
    29         s.pop();
    30         for(int j = 0; j < Map[now].size(); j++)
    31         {
    32             if((--Count[Map[now][j]]) == 0)
    33             {
    34                 s.push(Map[now][j]);
    35             }
    36         }
    37     }
    38     if(v.size() != n)cout<<"Network has a cycle!"<<endl;
    39     else
    40     {
    41         cout<<"Great! There is not cycle."<<endl;
    42         for(int i = 0; i < v.size(); i++)cout<<v[i]<<" ";
    43         cout<<endl;
    44     }
    45 }
    46 int main()
    47 {
    48     while(cin >> n >> m)
    49     {
    50         if(!n && !m)break;
    51         int u, v;
    52         for(int i = 0;  i <= n; i++)Map[i].clear();
    53         memset(Count, 0, sizeof(Count));
    54         for(int i = 0; i < m; i++)
    55         {
    56             cin >> u >> v;
    57             Map[u].push_back(v);
    58             Count[v]++;//存入度
    59         }
    60         topo();
    61     }
    62     return 0;
    63 }

     时间复杂度:由于每个点入栈出栈一次,每条边扫描一次,时间复杂度为O(m + n)

     
     
     
  • 相关阅读:
    熟悉常用的Linux操作
    组合数据类型练习
    简易的词法分析程序
    大数据概述
    201552040205 关于对java的体验与感悟
    对已学习的java内容的一些感悟
    关于java中的一些小技巧
    Javase 大纲2
    Javase大纲
    MysQL知识整理
  • 原文地址:https://www.cnblogs.com/fzl194/p/8747537.html
Copyright © 2011-2022 走看看