_DataStructure_C_Impl:AOE网的关键路径
//_DataStructure_C_Impl:CriticalPath
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"SeqStack.h"
//图的邻接表类型定义
typedef char VertexType[4];
typedef int InfoPtr; //定义为整型,为了存放权值
typedef int VRType; #define MaxSize 50 //最大顶点个数
typedef enum{DG,DN,UG,UN}GraphKind; //图的类型:有向图、有向网、无向图和无向网
//边结点的类型定义
typedef struct ArcNode{
int adjvex; //邻接点域,弧指向的顶点的位置
InfoPtr *info; //弧的权值
struct ArcNode *nextarc; //指示下一个与该顶点相邻接的顶点
}ArcNode;
//头结点的类型定义
typedef struct VNode{
VertexType data; //用于存储顶点
ArcNode *firstarc; //指示第一个与该顶点邻接的顶点
}VNode,AdjList[MaxSize];
//图的类型定义
typedef struct{
AdjList vertex;
int vexnum,arcnum; //图的顶点数目与弧的数目
GraphKind kind; //图的类型
}AdjGraph;
//返回图中顶点相应的位置
int LocateVertex(AdjGraph G,VertexType v){
int i;
for(i=0;i<G.vexnum;i++)
if(strcmp(G.vertex[i].data,v)==0)
return i;
return -1;
}
//採用邻接表存储结构,创建有向网N
void CreateGraph(AdjGraph *N){
int i,j,k,w;
VertexType v1,v2; //定义两个顶点v1和v2
ArcNode *p;
printf("请输入图的顶点数,边数(逗号分隔): ");
scanf("%d,%d",&(*N).vexnum,&(*N).arcnum);
printf("请输入%d个顶点的值:\n",N->vexnum);
for(i=0;i<N->vexnum;i++){
scanf("%s",N->vertex[i].data);
N->vertex[i].firstarc=NULL; //将相关联的顶点置为空
}
printf("请输入弧尾和弧头(以空格作为间隔):\n");
for(k=0;k<N->arcnum;k++){ //建立边链表
scanf("%s%s%*c%d",v1,v2,&w);
i=LocateVertex(*N,v1);
j=LocateVertex(*N,v2);
//j为弧头i为弧尾创建邻接表
p=(ArcNode *)malloc(sizeof(ArcNode));
p->adjvex=j;
p->info=(InfoPtr*)malloc(sizeof(InfoPtr));
*(p->info)=w;
//将p指向的结点插入到边表中
p->nextarc=N->vertex[i].firstarc;
N->vertex[i].firstarc=p;
}
(*N).kind=DN;
}
//销毁无向图G
void DestroyGraph(AdjGraph *G){
int i;
ArcNode *p,*q;
for(i=0;i<(*G).vexnum;++i){ //释放图中的边表结点
p=G->vertex[i].firstarc; //p指向边表的第一个结点
if(p!=NULL){ //假设边表不为空,则释放边表的结点
q=p->nextarc;
free(p);
p=q;
}
}
(*G).vexnum=0; //将顶点数置为0
(*G).arcnum=0; //将边的数目置为0
}
//输出图的邻接表
void DisplayGraph(AdjGraph G){
int i;
ArcNode *p;
printf("%d个顶点:\n",G.vexnum);
for(i=0;i<G.vexnum;i++)
printf("%s ",G.vertex[i].data);
printf("\n%d条边:\n",G.arcnum);
for(i=0;i<G.vexnum;i++)
{
p=G.vertex[i].firstarc;
while(p)
{
printf("<%s,%s,%d> ",G.vertex[i].data,G.vertex[p->adjvex].data,*(p->info));
p=p->nextarc;
}
printf("\n");
}
}
//*********************************************************
int ve[MaxSize]; //ve存放事件最早发生时间
/*採用邻接表存储结构的有向网N的拓扑排序,并求各顶点相应事件的最早发生时间ve*/
/*假设N无回路。则用用栈T返回N的一个拓扑序列,并返回1,否则为0*/
int TopologicalOrder(AdjGraph N,SeqStack *T){
int i,k,count=0;
int indegree[MaxSize]; //数组indegree存储各顶点的入度
SeqStack S;
ArcNode *p;
//将图中各顶点的入度保存在数组indegree中
for(i=0;i<N.vexnum;i++) //将数组indegree赋初值
indegree[i]=0;
for(i=0;i<N.vexnum;i++){
p=N.vertex[i].firstarc;
while(p!=NULL){
k=p->adjvex;
indegree[k]++;
p=p->nextarc;
}
}
//初始化栈S
InitStack(&S);
printf("拓扑序列:");
for(i=0;i<N.vexnum;i++)
if(!indegree[i]) //将入度为零的顶点入栈
PushStack(&S,i);
InitStack(T); //初始化逆拓扑排序顶点栈
for(i=0;i<N.vexnum;i++) //初始化ve
ve[i]=0;
while(!StackEmpty(S)){ //假设栈S不为空
PopStack(&S,&i); //从栈S将已拓扑排序的顶点i弹出
printf("%s ",N.vertex[i].data);
PushStack(T,i); //i号顶点入逆拓扑排序栈T
count++; //对入栈T的顶点计数
for(p=N.vertex[i].firstarc;p;p=p->nextarc){ //处理编号为i的顶点的每一个邻接点
k=p->adjvex; //顶点序号为k
if(--indegree[k]==0) //假设k的入度减1后变为0,则将k入栈S
PushStack(&S,k);
if(ve[i]+*(p->info)>ve[k]) //计算顶点k相应的事件的最早发生时间
ve[k]=ve[i]+*(p->info);
}
}
if(count<N.vexnum){
printf("该有向网有回路\n");
return 0;
}else
return 1;
}
//输出AOE网N的关键路径
int CriticalPath(AdjGraph N){
int vl[MaxSize]; //事件最晚发生时间
SeqStack T;
int i,j,k,e,l,dut,value,count,e1[MaxSize],e2[MaxSize];
ArcNode *p;
if(!TopologicalOrder(N,&T)) //假设有环存在,则返回0
return 0;
value=ve[0];
for(i=1;i<N.vexnum;i++)
if(ve[i]>value)
value=ve[i]; //value为事件的最早发生时间的最大值
for(i=0;i<N.vexnum;i++) //将顶点事件的最晚发生时间初始化
vl[i]=value;
while(!StackEmpty(T)) //按逆拓扑排序求各顶点的vl值
for(PopStack(&T,&j),p=N.vertex[j].firstarc;p;p=p->nextarc){ //弹出栈T的元素,赋给j,p指向j的后继事件k
k=p->adjvex;
dut=*(p->info); //dut为弧<j,k>的权值
if(vl[k]-dut<vl[j])//计算事件j的最迟发生时间
vl[j]=vl[k]-dut;
}
printf("\n事件的最早发生时间和最晚发生时间\ni ve[i] vl[i]\n");
for(i=0;i<N.vexnum;i++) //输出顶点相应的事件的最早发生时间最晚发生时间
printf("%d %d %d\n",i,ve[i],vl[i]);
printf("关键路径为:(");
for(i=0;i<N.vexnum;i++) //输出关键路径经过的顶点
if(ve[i]==vl[i])
printf("%s ",N.vertex[i].data);
printf(")\n");
count=0;
printf("活动最早開始时间和最晚開始时间\n 弧 e l l-e\n");
for(j=0;j<N.vexnum;j++)
for(p=N.vertex[j].firstarc;p;p=p->nextarc){
k=p->adjvex;
dut=*(p->info); //dut为弧<j,k>的权值
e=ve[j]; //e就是活动<j,k>的最早開始时间
l=vl[k]-dut; //l就是活动<j,k>的最晚開始时间
printf("%s→%s %3d %3d %3d\n",N.vertex[j].data,N.vertex[k].data,e,l,l-e);
if(e==l){ //将关键活动保存在数组中
e1[count]=j;
e2[count]=k;
count++;
}
}
printf("关键活动为:");
for(k=0;k<count;k++) //输出关键路径
{
i=e1[k];
j=e2[k];
printf("(%s→%s) ",N.vertex[i].data,N.vertex[j].data);
}
printf("\n");
return 1;
}
void main(){
AdjGraph N;
CreateGraph(&N); /*採用邻接表存储结构创建有向网N*/
DisplayGraph(N); /*输出有向网N*/
CriticalPath(N); /*求网N的关键路径*/
DestroyGraph(&N); /*销毁网N*/
system("pause");
}
#pragma once
#include<stdio.h>
#include<stdlib.h>
#define StackSize 100
typedef int DataType; //栈元素类型定义
typedef struct{
DataType stack[StackSize];
int top;
}SeqStack;
//将栈初始化为空栈仅仅须要把栈顶指针top置为
void InitStack(SeqStack *S){
S->top=0;//把栈顶指针置为0
}
//推断栈是否为空。栈为空返回1,否则返回0
int StackEmpty(SeqStack S){
if(S.top==0)
return 1;
else
return 0;
}
//取栈顶元素。将栈顶元素值返回给e,并返回1表示成功;否则返回0表示失败。
int GetTop(SeqStack S,DataType *e){
if(S.top<=0){ //在取栈顶元素之前。推断栈是否为空
printf("栈已经空!\n");
return 0;
}else{
*e=S.stack[S.top-1]; //在取栈顶元素
return 1;
}
}
//将元素e进栈。元素进栈成功返回1,否则返回0
int PushStack(SeqStack *S,DataType e){
if(S->top>=StackSize){ //在元素进栈前,推断是否栈已经满
printf("栈已满。不能进栈! \n");
return 0;
}else{
S->stack[S->top]=e; //元素e进栈
S->top++; //改动栈顶指针
return 1;
}
}
//出栈操作。将栈顶元素出栈。并将其赋值给e。出栈成功返回1。否则返回0
int PopStack(SeqStack *S,DataType *e){
if(S->top<=0){ //元素出栈之前,推断栈是否为空
printf("栈已经没有元素,不能出栈!\n");
return 0;
}else{
S->top--; //先改动栈顶指针。即出栈
*e=S->stack[S->top]; //将出栈元素赋值给e
return 1;
}
}
//求栈的长度。即栈中元素个数,栈顶指针的值就等于栈中元素的个数
int StackLength(SeqStack S){
return S.top;
}
//清空栈的操作
void ClearStack(SeqStack *S){
S->top=0;
}
_DataStructure_C_Impl:AOE网的关键路径的更多相关文章
- AOE网与关键路径简介
前面我们说过的拓扑排序主要是为解决一个工程能否顺序进行的问题,但有时我们还需要解决工程完成需要的最短时间问题.如果我们要对一个流程图获得最短时间,就必须要分析它们的拓扑关系,并且找到当中最关键的流程, ...
- 基于AOE网的关键路径的求解
[1]关键路径 在我的经验意识深处,“关键”二字一般都是指临界点. 凡事万物都遵循一个度的问题,那么存在度就会自然有临界点. 关键路径也正是研究这个临界点的问题. 在学习关键路径前,先了解一个AOV网 ...
- AOE网与关键路径
声明:图片及内容基于https://www.bilibili.com/video/BV1BZ4y1T7Yx?from=articleDetail 原理 AOE网 关键路径 数据结构 核心代码 Topo ...
- AOE网的关键路径的计算
求关键路径,只需理解顶点(事件)和边(活动)各自的两个特征属性以及求法即可: Ø 先根据首结点的Ve(j)=0由前向后(正拓扑序列)计算各顶点的最早发生时间 Ø 再根据终结点的Vl(j)等于它的V ...
- 教你轻松计算AOE网关键路径(转)
原文链接:http://blog.csdn.net/wang379275614/article/details/13990163 本次结合系统分析师-运筹方法-网络规划技术-关键路径章节,对原文链接描 ...
- 教你轻松计算AOE网关键路径
认识AOE网 有向图中,用顶点表示活动,用有向边表示活动之间开始的先后顺序,则称这种有向图为AOV网络:AOV网络可以反应任务完成的先后顺序(拓扑排序). 在AOV网的边上加上权值表示完成该活动所需的 ...
- SDUT 2498 AOE网上的关键路径
AOE网上的关键路径 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 一个无环的有向图称为无 ...
- 数据结构关于AOV与AOE网的区别
AOV网,顶点表示活动,弧表示活动间的优先关系的有向图. 即如果a->b,那么a是b的先决条件. AOE网,边表示活动,是一个带权的有向无环图, 其中顶点表示事件,弧表示活动,权表示活动持续时间 ...
- AOV图与拓扑排序&AOE图与关键路径
AOV网:所有的工程或者某种流程可以分为若干个小的工程或阶段,这些小的工程或阶段就称为活动.若以图中的顶点来表示活动,有向边表示活动之间的优先关系,则这样活动在顶点上的有向图称为AOV网. 拓扑排序算 ...
随机推荐
- java javax.annotation.Resource注解的详解
转自:https://www.jb51.net/article/95456.htm java 注解:java javax.annotation.Resource 当我们在xml里面为类配置注入对象时 ...
- Html+CSS基础之Html
注:本文摘自慕课网http://www.imooc.com HTML+CSS基础课程 本人有道笔记:http://note.youdao.com/noteshare?id=18fa811e9f9e ...
- 抽象类(abrstract class)与接口(interface)有何异同
抽象类:如果一个类中包含抽象方法(用abstract修饰的方法),那么这个类就是抽象类 接口:是指一个方法的集合,接口中的所有方法都没有方法体 相同点: 1)都不能被实例化 2)接口的实现类或抽象类的 ...
- TopN问题(分别使用Hadoop和Spark实现)
简介 TopN算法是一个经典的算法,由于每个map都只是实现了本地的TopN算法,而假设map有M个,在归约的阶段只有M x N个,这个结果是可以接受的并不会造成性能瓶颈. 这个TopN算法在map阶 ...
- C#使用SqlTransaction事务回滚与SqlBulkCopy批量插入数据
C#中批量处理数据,有时候因为一条记录导致整个批量处理失败.这时候肯能会导致数据不全等问题,这时候我们可以使用SqlTransaction来进行事务回滚,即是要么全部成功要么全部不成功.如下代码 // ...
- 3) 十分钟学会android--建立第一个APP,建立简单的用户界面
在本小节里,我们将学习如何用 XML 创建一个带有文本输入框和按钮的界面.下一节课将学会使 APP 对按钮做出响应——按钮被按下时,文本框里的内容被发送到另外一个 Activity. Android ...
- Struts2框架学习(三)——配置详解
一.struts.xml配置 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts ...
- JDK1.7源码阅读tools包之------ArrayList,LinkedList,HashMap,TreeMap
1.HashMap 特点:基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 Has ...
- QT与openCV,与PCL结合!
(1):详解QT多媒体框架:给予视频播放器 原文链接:http://mobile.51cto.com/symbian-271123.htm 对于使用主框架的QT程序,实现Qimage的转换可借鉴下面程 ...
- JS中的map
定义和用法: map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值. map() 方法按照原始数组元素顺序依次处理元素. 注意: map() 不会对空数组进行检测. 注意: m ...