【AOV网】

日常生活中,一项大的工程可以看作是由若干个子工程组成的集合,这些子工程之间必定存在一定的先后顺序,即某些子工程必须在其他的一些子工程完成后才能开始。

我们用有向图来表现子工程之间的先后关系,子工程之间的先后关系为有向边,这种有向图称为“顶点活动网络”,即:AOV 网。

一个有向无环图称为无环图(Directed Acyclic Graph),简称 DAG 图,因此一个 AOV 网必定是一个有向无环图,即不带有回路。与 DAG 不同的是,AOV 的活动都表示在边上。

如下图,共有11项活动(11条边),9个事件(9个点),只有一个源点(入度为零的点)和一个汇点(一个出度为零的点),路径的长度是边上活动耗费的时间,则可定义概念——关键路径:从源点到汇点的最长路径的长度,下图中的:1-2-5-7-9 即为一条关键路径,权值的和为18。

【基本概念】

  1. 活动:子工程组成的集合,每个子工程即为一个活动。
  2. 前驱活动:有向边起点的活动称为终点的前驱活动(只有当一个活动的前驱全部都完成后,这个活动才能进行)。
  3. 后继活动:有向边终点的活动称为起点的后继活动。
  4. 拓扑排序:将 AOV 网中所有活动排成一个序列,使得每个活动的前驱活动都排在该活动的前面。
  5. 拓扑序列:经过拓扑排序后得到的活动序列(一个 AOV 网的拓扑序列不是唯一的)。
  6. 关键路径:AOV 网中从源点到汇点的最长路径的长度(一个 AOV 网中的拓扑排序不是唯一的)。

【拓扑排序思想】

  1. 选择一个入度为 0 的顶点并输出。
  2. 从 AOV 网中删除此顶点及以此顶点为起点的所有关联边。
  3. 重复上述两步,直到不存在入度为 0 的顶点为止。
  4. 若输出的顶点数小于 AOV 网中的顶点数,则说明 AOV 网中回路,不是一个标准的 AOV 网。

【算法分析】

以下图为例

开始时,只有 A 入度为 0,A 入栈。

栈:A

栈顶元素 A 出栈,输出 A,A 的后继节点 B、C 入度减 1(相当于删除 A 的所有关联边)。

栈:空

拓扑序列:A

B、C 入度都为 0,依次将  B、C 入栈

栈:BC(入栈顺序不唯一)

拓扑序列:A

栈顶元素 C 出栈,输出 C,C 的后继结点 D 入度减 1(相当于删除 C 的所有关联边)。

栈:B

拓扑序列:AC

栈顶元素 B 出栈,输出 B,B 的后继结点 D 入度减 1(相当于删除 B 的所有关联边),此时 D 的入度为 0,入栈。

栈:D

拓扑序列:ACB

栈顶元素 D 出栈,输出 D。

栈:空

拓扑序列:ACBD(不唯一)

【AOV 网的判定】

有时,给出一个 n 个点 m 条边的有向图,需要判定图是否是 AOV 网,也即判断图是否可以进行拓扑排序。

一个有向图无法进行拓扑排序时只有一种情况:该有向图中存在环。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
#define N 10001
using namespace std;
int n,m;
int in[N];//节点入度
vector<int> G[N];//G[i]表示i节点所指向的所有其他点
bool judgeTopsort()//判断该图是否可拓扑排序
{stack<int> S;int cnt=0;//记录可拆解的点数目for(int i=1;i<=n;i++)//枚举编号从1到n的点if(in[i]==0)//入度为0,入栈S.push(i);while(!S.empty()) {int x=S.top();//取栈顶元素S.pop();cnt++;//可拆点数+1for(int i=0;i<G[x].size();i++){int y=G[x][i];in[y]--;//入度减一if(in[y]==0)//入度为0,出栈S.push(y);}}if(cnt==n)//AOV网点数等于图的点数,不存在环,可进行拓扑排序return true;else//AOV网点数等于图的点数,存在环,不可进行拓扑排序return false;
}
int main()
{while(scanf("%d%d",&n,&m)==2&&n){memset(in,0,sizeof(in));for(int i=1;i<=n;i++)G[i].clear();while(m--) {int x,y;scanf("%d%d",&x,&y);G[x].push_back(y);in[y]++;}printf("%s\n",judgeTopsort()?"YES":"NO");}return 0;
}

【拓扑排序的输出】

1.输出任意一条拓扑排序结果

当给出一 n 个点 m 条边的有向边时,要输出一个可行的点的拓扑序列,此时可根据上述的 AOV 网判定代码,修改后存储路径输出即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
#define N 10001
using namespace std;
int n,m;
int in[N];//节点入度
int path[N];//存储路径
vector<int> G[N];//G[i]表示i节点所指向的所有其他点
void Topsort()//拓扑排序
{stack<int> S;int cnt=0;//记录可拆解的点数目for(int i=1;i<=n;i++)//枚举编号从1到n的点if(in[i]==0)//入度为0,入栈S.push(i);while(!S.empty()) {int x=S.top();//取栈顶元素S.pop();path[++cnt]=x;//存储可拆点for(int i=0;i<G[x].size();i++){int y=G[x][i];in[y]--;//入度减一if(in[y]==0)//入度为0,出栈S.push(y);}}
}
int main()
{while(scanf("%d%d",&n,&m)==2&&n){memset(in,0,sizeof(in));for(int i=1;i<=n;i++)G[i].clear();while(m--) {int x,y;scanf("%d%d",&x,&y);G[x].push_back(y);in[y]++;}Topsort();for(int i=1;i<=n;i++)printf("%d ",path[i]);printf("\n");}return 0;
}

2.输出按字典序最小的拓扑排序结果

求字典序最小的拓扑序列时,要用优先队列,且是最小值优先的队列,其大致思想是队列 Q 总是将当前在入度为 0 的最小节点优先取出,从而保证了字典序最小。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define N 10001
using namespace std;
int n,m;
int in[N];//节点入度
int path[N];//存储路径
vector<int> G[N];//G[i]表示i节点所指向的所有其他点
void Topsort()//拓扑排序
{priority_queue< int,vector<int>,greater<int> > Q;//最小值先出列int cnt=0;//记录可拆解的点数目for(int i=1;i<=n;i++)//枚举编号从1到n的点if(in[i]==0)//入度为0,入列Q.push(i);while(!Q.empty()) {int x=Q.top();//队列首元素Q.pop();path[++cnt]=x;//存储可拆点for(int i=0;i<G[x].size();i++){int y=G[x][i];in[y]--;//入度减一if(in[y]==0)//入度为0,出列Q.push(y);}}
}
int main()
{while(scanf("%d%d",&n,&m)!=EOF&&n){memset(in,0,sizeof(in));for(int i=1;i<=n;i++)G[i].clear();for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);G[x].push_back(y);in[y]++;}Topsort();for(int i=1;i<=n;i++)printf("%d ",path[i]);printf("\n");}return 0;
}

【例题】

1.拓扑排序的判定

  1. Legal or Not(HDU-3342):点击这里
  2. Triangle LOVE(HDU-4324):点击这里

2.输出拓扑排序结果

  1. Genealogical tree(POJ-2367)(输出任一条拓扑排序结果):点击这里
  2. 确定比赛名次(HDU-1285)(输出字典序最小的拓扑排序结果):点击这里
  3. Following Orders(POJ-1270)(按字典序输出所有拓扑排序结果):点击这里

3.拓扑排序的应用

  1. 烦人的幻灯片(信息奥赛一本通-T1395)(拓扑排序思想):点击这里
  2. 家谱树(信息奥赛一本通-T1351)(构造拓扑排序):点击这里
  3. 奖金(信息奥赛一本通-T1352)(构造拓扑排序):点击这里
  4. Cow Traffic(POJ-3272)(双向拓扑排序):点击这里
  5. Ponds(HDU-5438)(拓扑排序删点+dfs):点击这里
  6. 病毒(信息奥赛一本通-T1396)(给出字典序,找出拓扑排序关系):点击这里
  7. 处女座的比赛资格(2019牛客寒假算法基础集训营 Day3-B)(拓扑排序求最短路):点击这里
  8. Sorting It All Out(POJ-1094)(拓扑排序+差分约束系统):点击这里
  9. Labeling Balls(POJ-3687)(拓扑排序+逆向思维):点击这里

图论 —— AOV 网与拓扑排序相关推荐

  1. 有向无环图——AOV网及拓扑排序

    有向无环图--AOV网及拓扑排序 有向无环图 无环的有向图叫有向无环图,简称DAG图 其应用大致如下: 在工程计划和管理方面有着广泛而重要的应用 描述一项工程或系统的进行进程的有效工具 对整个工程和系 ...

  2. 图论——AOV网络及拓扑排序

    引入 有向无环图(DAG) 如果一个有向图不存在环,也就是任意结点都无法通过一些有向边回到自身,那么称这个有向图为有向无环图 AOV 网络 在有向图中,用顶点表示活动,用有向边<Vi,Vj> ...

  3. 拓扑排序之AOV网及其拓扑排序思想(C语言)

    一.拓扑排序 (一)AOV⽹ AOV网(Activity On Vertex NetWork,⽤顶点表示活动的网):用DAG图(有向无环图)表示⼀个⼯程.顶点表示活动,有向边<Vi, Vj> ...

  4. C语言-AOV网与拓扑排序

    邻接表: 顶点下标查找函数(LocateVex) 创建有向图的邻接表(CreateDG) 邻接表打印函数(print) 拓扑排序(TopologicalSort) AOV网与AOE网: AOV网(Ac ...

  5. AOV网络、拓扑排序、拓扑序列

    AOV网络 AOV网是有向图的一类应用,在AOV网中,用顶点表示某个有一定规模的"工程"里的不同活动,用图中的边表示各项活动之间的先后顺序关系.一种常见的AOV网实例是大学课程的先 ...

  6. 图算法入门3:活动网络-AOV网络和拓扑排序

    AOV网络 通常一个工程可以分成若干个子工程,这些子工程被称为活动(activity),完成这些活动,整个工程就完成了.给一个简单的例子,如下图,大学专业课程存在依赖关系,对于一些课程必须选修其他课程 ...

  7. 图论算法—图的拓扑排序介绍和Kahn算法原理解析以及Java代码的实现

    详细介绍了图的拓扑排序的概念,然后介绍了求拓扑序列的算法:Kahn算法的原理,最后提供了基于邻接矩阵和邻接表的图对该算法的Java实现. 阅读本文需要一定的图的基础,如果对于图不是太明白的可以看看这篇 ...

  8. 【题解】(图论) —— POJ 0719:拓扑排序

    题目链接:OpenJudge - 0719:拓扑排序 总时间限制: 10000ms 内存限制: 1000kB 描述 给出一个图的结构,输出其拓扑排序序列,要求在同等条件下,编号小的顶点在前 输入 若干 ...

  9. 数据结构与算法A实验六图论---7-7 最短工期 (拓扑排序)

    一个项目由若干个任务组成,任务之间有先后依赖顺序.项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务.现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工 ...

最新文章

  1. 【Deep Learning笔记】前馈神经网络和BP算法
  2. 成功解决on line , but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
  3. Java程序员需要掌握的计算机底层知识(三):进程、线程、纤程、中断
  4. selenium 等待_Selenium等待:内隐,外显,流利和睡眠
  5. 迁移分支_资料 | 迁移学习简明手册
  6. 数组复制速度 System.arraycopy()clone() Arrays.copyof() for()探究
  7. 2021年中国单硝酸异山梨酯市场趋势报告、技术动态创新及2027年市场预测
  8. 利用正则计算输入内容的长度
  9. 第4章 最基础的分类算法-k近邻算法 kNN 学习笔记 上
  10. [推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到)
  11. python编程之条形码生成大全
  12. 齐次线性方程组、齐次方程、齐次多项式
  13. 25岁,一个北漂程序员,如果不想35 岁被淘汰,请把它当成一种信仰!
  14. 《左耳听风》-ARTS-打卡记录-第二十五周
  15. java 二进制 2个字节 高位 低位_高位字节、低位字节
  16. 数据库管理 │ 浅谈从集中式到分布式数据库的转型要点
  17. 计算机控制adda转换实验报告,ADDA实验报告
  18. Java语言对于大数据而言是什么样的存在?
  19. 【JY】结构工程师:请避开有限元分析中6个常见的“坑”
  20. 牛客网JS(nodeJS)单行、多行输入和输出

热门文章

  1. 立创eda专业版学习笔记(6)(pcb板移动节点)
  2. 写一个python脚本控制微信企业版的群聊机器人完成番茄工作法的闹钟通知
  3. java怎么设置窗体标题_Android窗体自定义标题栏
  4. Spring-boot state-machine 状态机 papyrus 详细操作步骤
  5. 机器人制作入门--初学者
  6. Qt制作一个运动的钟表
  7. STM32下315M模块的无线接收解码程序
  8. 一种监狱室内人员定位解决方案-室内人员定位-新导智能
  9. idea 重新下载jar
  10. 使用Amazon SageMaker 构建基于自然语言处理的文本摘要应用