//_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网的关键路径的更多相关文章

  1. AOE网与关键路径简介

    前面我们说过的拓扑排序主要是为解决一个工程能否顺序进行的问题,但有时我们还需要解决工程完成需要的最短时间问题.如果我们要对一个流程图获得最短时间,就必须要分析它们的拓扑关系,并且找到当中最关键的流程, ...

  2. 基于AOE网的关键路径的求解

    [1]关键路径 在我的经验意识深处,“关键”二字一般都是指临界点. 凡事万物都遵循一个度的问题,那么存在度就会自然有临界点. 关键路径也正是研究这个临界点的问题. 在学习关键路径前,先了解一个AOV网 ...

  3. AOE网与关键路径

    声明:图片及内容基于https://www.bilibili.com/video/BV1BZ4y1T7Yx?from=articleDetail 原理 AOE网 关键路径 数据结构 核心代码 Topo ...

  4. AOE网的关键路径的计算

    求关键路径,只需理解顶点(事件)和边(活动)各自的两个特征属性以及求法即可: Ø  先根据首结点的Ve(j)=0由前向后(正拓扑序列)计算各顶点的最早发生时间 Ø  再根据终结点的Vl(j)等于它的V ...

  5. 教你轻松计算AOE网关键路径(转)

    原文链接:http://blog.csdn.net/wang379275614/article/details/13990163 本次结合系统分析师-运筹方法-网络规划技术-关键路径章节,对原文链接描 ...

  6. 教你轻松计算AOE网关键路径

    认识AOE网 有向图中,用顶点表示活动,用有向边表示活动之间开始的先后顺序,则称这种有向图为AOV网络:AOV网络可以反应任务完成的先后顺序(拓扑排序). 在AOV网的边上加上权值表示完成该活动所需的 ...

  7. SDUT 2498 AOE网上的关键路径

    AOE网上的关键路径 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 一个无环的有向图称为无 ...

  8. 数据结构关于AOV与AOE网的区别

    AOV网,顶点表示活动,弧表示活动间的优先关系的有向图. 即如果a->b,那么a是b的先决条件. AOE网,边表示活动,是一个带权的有向无环图, 其中顶点表示事件,弧表示活动,权表示活动持续时间 ...

  9. AOV图与拓扑排序&AOE图与关键路径

    AOV网:所有的工程或者某种流程可以分为若干个小的工程或阶段,这些小的工程或阶段就称为活动.若以图中的顶点来表示活动,有向边表示活动之间的优先关系,则这样活动在顶点上的有向图称为AOV网. 拓扑排序算 ...

随机推荐

  1. 用Webpack构建Vue项目

    开始之前,需要安装node环境.(安装过程在此就不啰嗦了)   1.创建基本结构 首先我们要创建一个空文件夹(我这里叫todos,你可以随便命名)作为项目的根目录. 创建一个没有任何依赖关系的pack ...

  2. JS+jquery 计算服务器控件textbox的值并显示在lable上

    更好的方法求共同学习. //通用            function Change(clientId) {                var sampleQuantity = $(" ...

  3. Sybase 动态改变存储过程里查询的数据库

    declare @sql varchar(500) select @sql='select * from '+@dbName+'..tableName' --此句用于执行拼接好的SQL语句 exec( ...

  4. css网页布局方式的理解

    一,标准流(默认状态,元素盒按照文档中出现的顺序排列) 块级元素--垂直排版 display:block; 单独一行,可以设置宽高,宽度默认和父元素宽度一致 一般结构性标记都为块级元素,如div,h, ...

  5. sql server<> != 从数据类型varchar转换为numeric 时出错

    sql server 数据类型转换出错 字段percentcomplete 是 varchar 类型, 都是存的数字 用 where cast(percentcomplete as numeric(1 ...

  6. MongoDB(二)创建更新删除文档

    插入并保存文档操作 用insert向目标集合插入文档,如果没有_id键则会自动添加.最后自动保存. >db.foo.insert({"bar":"baz" ...

  7. Win8.1应用开发之适配器模式(C#实现)

    实际上适配器模式是用于解耦.设想一下我们的程序模块A在与模块B打交道时,需要在许多地方多次使用B中某个类的方法,而负责开发B的程序猿Tom还未完全实现该类,会随时更改该类中的方法,那么当Tom在修改时 ...

  8. MeayunDB学习笔记(一) MeayunDB介绍及安装

    系列目录   MeayunDB介绍-高性能分布式内存数据库 MeayunDB学习笔记(一)MeayunDB介绍及安装 MeayunDB学习笔记(二)批量导入数据 MeayunDB学习笔记(三)索引应用 ...

  9. AI:**消灭程序员需要一百年吗?

    这篇博文真的很长,不过挺有意思.关于智能机器人的发展前景还是很广的,因为每一步都异常艰难,而什么时候可以终止还无法预料,所以程序员没办法失业啊! 转自于图灵社区:http://www.ituring. ...

  10. Linux 中文件名颜色所代表的属性

    1. 白色:表示一般文件 2. 蓝色:表示目录 3. 绿色:表示可执行的文件或程序 4. 浅蓝色:表示链接文件 5. 黄色:表示设备文件 6. 灰色:表示其他类型文件 7. 红色:表示压缩文件或者包文 ...