活动网络

  • 7.6.1 用顶点表示活动的网络AOV
    • 问题的提出
    • 相关定义
    • 拓扑排序算法
      • 存储结构
      • 算法步骤
      • 算法实现
        • 拓扑算法
      • 效率分析
    • 思考:
    • 其他资料转载

7.6.1 用顶点表示活动的网络AOV

问题的提出

学生选修课程问题

顶点,表示课程
有向弧,表示先决条件,若课程i是课程j的先决条件,则图中有弧<i,j>
学生应按怎样的顺序学习这些课程,才能无矛盾、顺利地完成学业——拓扑排序

相关定义

  1. 有向无环图(directed acycline graph),简称DAG图

    第二个图没有环,是DAG,第三个图有环,只能成为有向图
  2. 顶点表示活动(activity on vertices AOV)的网络
    AOV是用以表示一个工程的有向图
    图中的顶点表示一项子工程,即活动
    弧表示两活动之间的先后次序
    以计算机专业课程学习工程为例:
  3. 拓扑排序(Topological Sort):把AOV网络中各顶点按照它们相互之间的优先关系排列成一个线性序列的过程。
    检测AOV网中是否存在环方法:对有向图构造其顶点的拓扑有序序列,若网中所有顶点都在它的拓扑有序序列中,则该AOV网必定不存在环。
    (存在换的话,意味着某项活动的开始要以自己的完成作为先决条件,这显然是矛盾的)因此,对给定的AOV网络,必须先判断它是否存在有向环。
    拓扑排序的方法
    (1)在有向图中选一个没有前驱的顶点且输出之
    (2)从图中删除该顶点和所有以它为尾的弧(3)重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止。
    注意:如果顶点有多个直接后继,排序结果通常不唯一。即,拓扑排序的结果唯一的情况是:每个顶点有唯一的前驱后继关系。
    例如在下图中,存在两个拓扑有序序列,则说明拓扑排序不唯一。

    C1,C2,C3,C4,C5,C6,C8,C9,C7
    C1,C8,C9,C2,C5,C3,C7,C4,C6
    时间复杂度O(n+e)

拓扑排序算法

存储结构

AOV网络:邻接表
辅助变量:顶点入度数组InDegree[ ],记录各个顶点的入度

算法步骤

(1)建立入度为零的顶点栈;
(2)当入度为零的顶点栈为空时算法转步骤(6),否则继续步骤(3);
(3)入度为零的顶点栈中栈顶元素v出栈,并输出顶点v;
(4)从AOV网络中删去顶点v和所有从顶点v发出的弧<v , j >,并将顶点j的入度减一;
(5)如果顶点 j 入度减至0,则将该顶点进入入度为零的顶点栈;转步骤(2);
(6)如果输出顶点个数少于AOV网络的顶点个数,则输出网络中存在有向环的信息;算法结束。

算法实现

  1. 边节点类
template<class arcType> class ArcNode
{public:int vex;ArcNode<arcType> *nextarc;ArcNode(){nextarc=NULL;}ArcNode(int v,ArcNode<arcType> *next=NULL){vex=v;nextarc=next;}
};
  1. 顶点节点类
#include "ArcNode.h"
template<class vertexType,class ArcType> class VertexNode
{public:vertexType vertex;ArcNode<ArcType> *arcs;VertexNode(){arcs=NULL;}VertexNode(vertexType v){vertex=v;arcs=NULL;}
};
  1. 拓朴排序特殊邻接表(删除一些不必操作)实现
#define MaxVertexes 20
#include <iostream>
#include "VertexNode.h"
#include "ArcNode.h"using namespace std;template<class vertexType,class arcType> class VertexNode;
template<class arcType> class ArcNode;class Graph
{friend class VertexNode<int,int>;friend class ArcNode<int>;
private:VertexNode<int,int> *VertexesTable;int *InDegree;int CurrentNumVertexes;int CurrentNumArcs;//int GetVertexPos(const int &v);void Clear();public:Graph(int v[],int num=MaxVertexes);~Graph();void InsertVertex(int v);void InsertArc(int head,int tail);void Show()const;void TopologicalOrder();};
int Graph::GetVertexPos(const int &v)
{int i;for(i=0; i<CurrentNumVertexes && VertexesTable[i].vertex!=v; i++);if(i>=CurrentNumVertexes){cout<<"没有顶点的值为 "<<v<<" ,返回-1"<<endl;i=-1;}elsereturn i;
}
void Graph::InsertVertex(int v)
{int i;for(i=0; i<MaxVertexes; i++)if(VertexesTable[i].vertex==-1){VertexesTable[i].vertex=v;InDegree[i]=0;CurrentNumVertexes++;break;}if(i>=MaxVertexes){cout<<"顶点已满。"<<endl;}return;
}
void Graph::InsertArc(int head,int tail)
{if(VertexesTable[head].arcs==NULL){VertexesTable[head].arcs=new ArcNode<int>(tail);InDegree[tail]++;return;}ArcNode<int> *p=VertexesTable[head].arcs,*q=NULL;while(p!=NULL){if(p->vex==tail){cout<<"该顶点已在表中 "<<endl;return;}else{q=p;p=p->nextarc;}}q->nextarc=new ArcNode<int>(tail);CurrentNumArcs++;InDegree[tail]++;
}
Graph::Graph(int v[],int num):CurrentNumVertexes(0),CurrentNumArcs(0)
{int i;VertexesTable=new VertexNode<int,int>[MaxVertexes];InDegree=new int[MaxVertexes];for(i=0; i<MaxVertexes; i++) //初始化{VertexesTable[i].vertex=-1;InDegree[i]=0;}for(i=0; i<num; i++) //输入各顶点信息InsertVertex(v[i]);
}
void Graph::Clear()
{int i;ArcNode<int> *p=NULL,*q=NULL;for(i=0; i<CurrentNumVertexes; i++){p=VertexesTable[i].arcs;while(p!=NULL){q=p->nextarc;delete p;p=q;}p=NULL;q=NULL;VertexesTable[i].arcs=NULL;InDegree[i]=0;}CurrentNumArcs=0;CurrentNumVertexes=0;
}
Graph::~Graph()
{Clear();delete [] InDegree;delete [] VertexesTable;InDegree=NULL;VertexesTable=NULL;
}
void Graph::Show()const
{int i;ArcNode<int> *p=NULL;for(i=0; i<CurrentNumVertexes; i++){cout<<"第"<<i<<"个顶点("<<VertexesTable[i].vertex<<"),有边:";p=VertexesTable[i].arcs;while(p!=NULL){cout<<p->vex<<" -- ";p=p->nextarc;}cout<<"# ,入度为"<<InDegree[i]<<endl;}
}

拓扑算法

void Graph::TopologicalOrder()
{int i,j,count=0,top=-1;ArcNode<int> *p=NULL;for(i=0; i<CurrentNumVertexes; i++){if(InDegree[i]==0)///入度为0的顶点入栈{InDegree[i]=top;top=i;}}while(top!=-1)///栈非空{i=top;top=InDegree[i];cout<<VertexesTable[i].vertex<<" -- ";count++;///定点输出计数for(p=VertexesTable[i].arcs; p!=NULL; p=p->nextarc){j=p->vex;InDegree[j]--;if(InDegree[j]==0)//j入度为0,入栈{InDegree[j]=top;top=j;}}}cout<<"#"<<endl;if(count<CurrentNumVertexes)//有回路cout<<"图中有回路"<<endl;
}

测试结果:

效率分析

设AOV网络中有n个顶点和e条边,算法的第一个 for循环是搜索入度为零的顶点建立链栈,其所需要的时间是O(n)。
在拓扑排序的过程中,如果网络中没有回路,则网络中所有顶点都需要进一次栈,出一次栈,所需要的时向也是O(n)。顶点入度减1的运算共执行了e次。
所以拓扑排序算法的时间复杂度为O(n+e)

思考:

  1. 如何记录入度为0的顶点?采用什么结构/辅助手段比较好?
    【方法一】直接使用一个数组作为静态栈,栈的使用方式如下:
    (1)初始化栈,设置链初始值top为-1(表示空栈);
    (2)将入度为0的元素的进栈,即InDegree[v]=top;top=v;(当前节点入度值来保存前一个结点,用top指向最后进入的结点)
    (3)顶点入栈的同时“删除”前一个的出边(度数减一)。如果度数为0,继续压栈。
    (4)栈空top=-1,结束程序。判断是否有回路。
    【方法二】使用实现
    转载自:https://blog.csdn.net/Akatsuki__Itachi/article/details/80443778
void toposort()
{priority_queue<int,vector<int>,greater<int> >q;//当要求编号小的优先输出时用优先队列存储点for(int i=1;i<=n;i++)if(!num[i])q.push(i);int len=0;while(!q.empty()){int u=q.top();q.pop();ans[len++]=u;for(int i=0;i<v[u].size();i++){int t=v[u][i];num[t]--;if(!num[t])q.push(t);}}cout<<ans[0];for(int i=1;i<len;i++)cout<<" "<<ans[i];cout<<endl;
}

【方法三】使用队列实现
转载自:https://www.cnblogs.com/wkfvawl/p/9129325.html

#include<cstdio>
#include<cstring>
int ans[510][510];///邻接矩阵,记录二者是否有关联
int n,indegree[510];///记录节点个数
int queue[510];///保存拓扑
void topsort()
{int i,j,top,k=0;for(j=0; j<n; ++j)///遍历n次{for(i=1; i<=n; ++i){if(indegree[i]==0)///找到入度为0的节点{top=i;break;}}queue[k++]=top;///当前第一名入队列,也可以直接输出indegree[top]=-1;///该节点的入度更新为-1,避免重复入队列for(i=1; i<=n; ++i){if(ans[top][i])///删除与该店关联的边indegree[i]--;}}for(i=0; i<k-1; ++i)printf("%d ",queue[i]);printf("%d\n",queue[n-1]);
}int main()
{int i,a,b,m;while(scanf("%d%d",&n,&m)!=EOF){memset(indegree,0,sizeof(indegree));///数组初始化为0memset(ans,0,sizeof(ans));///数组初始化为0for(i=0; i<m; ++i){scanf("%d%d",&a,&b);if(ans[a][b]==0){ans[a][b]=1;///二者有关联indegree[b]++;///记录前驱数量}}topsort();}return 0;
}

可以采用队列来存储入度为0的顶点的原因? 在算法执行过程中,如果同时存在多个入度为0
的顶点,则首先选择删除哪个顶点不会影响算法的正确性。所以,在拓扑排序算法中,可以使用队列或栈来存储入度为0的顶点。
以上转自:https://www.cnblogs.com/wkfvawl/p/9876395.html


2. 理论上删去顶点的所有出边,实际的工程实现中是否真的删除边?如何处理?
利用度数数组减一。
3. 当有多个入度为0的顶点时,能否同时将它们记录下来并形成一种线性关系?采用什么结构/辅助手段比较好?
也是用链式栈记录前驱。

如果有向图的拓扑排序序列是唯一的,则图中必定只有一个顶点的入度为0,一个顶点的出度为0。(错)
只有一个顶点的入度为0,一个顶点的出度为0,不一定能得出唯一的拓扑排序。这是必要条件而不是充分条件。

其他资料转载

  1. 相关问题
    拓扑排序模板: 洛谷P1113 杂务.
    Floyed+拓扑排序: 洛谷P2419 USACO08JANCow Contest S.
    拓扑排序+思维(NOIP普及组考试题): 洛谷P1983 车站分级.
    真·拓扑排序 : 洛谷P1347 排序.
    以上转载自:https://blog.csdn.net/Berserker____/article/details/106733772
  2. 拓扑排序与BFS
    (1)拓扑排序与 BFS 算法的对比分析
    与用邻接表实现 BFS 算法的伪代码相比,拓扑排序与其有相似之处也有不同之处。
    相同点:拓扑排序实质上就是一种广度优先搜索,在算法执行过程中,通过栈顶顶点访问它的每个邻接点,整个算法执行过程中,每个顶点访问一次且仅一次,每条边扫描一次且仅一次。
    不同点:BFS 算法在扫描每条边时,如果边的终点没有访问过,则入队列;而拓扑排序算法在扫描每条边时,终点的入度要减 1,当减至 0 时才将该终点入栈。
    (2)拓扑排序与 BFS 算法栈或队列的使用
    请注意,在BFS 算法中是用队列来存储待扩展的顶点,在 拓扑排序算法中是用栈来存储入度为 0 的顶点。那么,在 BFS 算法中是否可以用栈来存储待扩展的顶点?在拓扑排序算法中是否可以用队列来存储入度为 0 的顶点?队列和栈的区别在于顶点出队列(或栈)的顺序,队列是先进先出,栈是后进先出。所以,能否用队列(或栈)关键要看这种顺序是否会影响算法的正确性。
    BFS 算法:如果用栈存储待扩展的顶点,如图所示,其中图(a)为正确的搜索过程,图(b)为用栈存储待扩展顶点时各顶点入栈和出栈的过程。在图(b)中,依次出栈的顶点是 A→E→D→F→H→I→B→C→G,很明显,这与 BFS 算法的实现过程和顶点访问顺序大相径庭。因此,在 BFS算法中不能用栈来存储待扩展的顶点。
    以上转载自:https://www.cnblogs.com/wkfvawl/p/9876395.html

活动网络——用顶点表示活动的网络AOV和拓扑相关推荐

  1. 网络爬虫-京东优惠活动数据分析

    作者介绍: 程虹升,唯品会大数据部数据分析师,数据分析和挖掘实战的践行者,"51CEO"公众号的运营者. 声明: 1. 该文章为技术类文章,部分同学可能对代码部分有所不适,可忽略代 ...

  2. 计算机试题及答案大学网络创业交流会,解析:在考生文件夹下打开文档WORD.DOCX。某高校学生会计划举办一场“大学生网络创业交流会”的活动,拟邀 - 计算机二级 - 看书网站...

    在考生文件夹下打开文档WORD.DOCX. 某高校学生会计划举办一场"大学生网络创业交流会"的活动,拟邀请部分专家和老师给在校学生进行演讲.因此,校学生会外联部需制作一批邀请函,并 ...

  3. 河北秦皇岛市委网信办开展“抵制网络谣言 净化网络空间”主题宣传活动

    为了提高广大市民网络素养,提升识谣辨谣能力,共建共享积极健康的网络生态环境,5月27日,河北省秦皇岛市委网信办走进海港区美岭社区开展"抵制网络谣言 净化网络空间"主题宣传活动.工作 ...

  4. 网络推广外包专员如何通过网络推广外包提升用户推送打开率?

    想必大家都了解企业网站活动推送功能对于传达企业活动信息变化的重要性,任何企业网站想要通过网络推广外包服务向用户推送信息活动,可通过精准的用户触达.渠道获取以及最大限度的向用户传达温暖,沟通企业网站与用 ...

  5. 网络营销外包专员浅析企业网络营销外包整合关键点有哪些?

    互联网技术的不断发展造就了当前网络市场的繁荣,在信息大爆炸的当下同行企业之间的竞争日益激烈,产品推入市场的速度也越来越快,企业为了实现抢占先机筛选攻略网络营销市场.在日常的网络营销中企业通过网络营销外 ...

  6. 网络工程师人手必备!常用网络命令合集请收下

    [欢迎关注微信公众号:厦门微思网络] 微思网络(官网):https://www.xmws.cn/ 在计算机网络中经常要对网络进行管理,测试,这时就要用到网络命令.今天就为大家整理了一些网络工程师必备的 ...

  7. 活动文档服务器,服务器 活动

    服务器 活动 内容精选 换一换 根据伸缩组ID查询指定弹性伸缩组详情.您可以在API Explorer中调试该接口.GET /autoscaling-api/v1/{project_id}/scali ...

  8. nmcli管理网络 RHEL8和CentOS8怎么重启网络

    1. 前言 本文主要讲解如何重启RHEL 8或者CentOS 8网络以及如何解决RHEL8和CentOS8系统的网络管理服务报错,当我们安装好RHEL 8或者 CentOS 8,重启启动网络时,会出现 ...

  9. 安卓网络连接全解:包括网络连接状态的监听、网络数据使用状态的监听、获取当前网络连接情况、启动wifi、获取当前连接wifi的网络情况、扫描wifi热点

    全栈工程师开发手册 (作者:栾鹏) 安卓教程全解 安卓网络连接情况全解:包括网络连接状态的监听.网络数据使用状态的监听.获取当前网络连接情况.启动wifi.获取当前连接wifi的网络情况.扫描wifi ...

  10. 重大网络教育计算机基础章节答案,网络教育计算机基础1答案

    计算机基础计算机基础 1 1 一 一 单项选择单项选择 1 完整的计算机系统由 C 组成 A 运算器 控制器 存储器 输入设备和输出设备 B 主机和外部设备 C 硬件系统和软件系统 D 主机箱 显示器 ...

最新文章

  1. 极限脱出 量子计算机,《极限脱出3:零时困境》50条指向zero身份线索
  2. .net中用css控制GridView样式
  3. 【重磅】中国AVS2标准被国际超高清联盟UHD Forum采纳,推荐给全球视频服务商
  4. 团队第二次冲刺第三天
  5. 原创《如何用vue来轻松的驾驭 html5 webapp的页面体验》
  6. 直播丨Oracle 12cR2 ADG LGWR Library Cache案例分享
  7. go 正则表达式分组匹配_Go语言正则表达式用法实例小结【查找、匹配、替换等】...
  8. jsf标签,jsp标签与jstl标签
  9. mysql router 多台写入_Centos7部署MySQL-router实现读写分离及从库负载均衡
  10. [GO]删除切片的某个值
  11. React Native 触摸事件处理详解
  12. 短语wipe the slate clean
  13. 只应对不预测、减少焦虑
  14. SharpShooter Reports.Web 7.5 Crack
  15. 【数据挖掘】基于SPSS Modeler实现商业银行信用卡贷款风险识别
  16. 游戏的本质【转自网易】
  17. 算法学习(2)----丢番图方程
  18. Kali开机后的初始化配置
  19. java中的日志处理
  20. PHP对接支付宝当面付详细教程

热门文章

  1. 新元宇宙奇科幻小说原创作品每周连载地球人奇游天球记第六回冬奥登月
  2. 2020秋招 携程算法岗笔试编程题解答
  3. 云上Java System Profiling与Debugging——蚂蚁金服观察与实践
  4. CISCO ASR9000 密码恢复
  5. 丽江,清晨的小巷在哭泣
  6. 拼接图像亮度均匀调整_浅析液晶拼接屏为什么适合应用于安防显示
  7. DID会固定年份吗_你了解渐进式DID平行趋势图的几种画法吗?
  8. 计算机网络上有个红叉没无线,如果计算机的无线网络上出现红叉指示连接不正确,该怎么办| WIFI显示红叉...
  9. 360随身wifi搭建无线热点
  10. tibco常用命令记录