_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网. 拓扑排序算 ...
随机推荐
- C++字符串与指针 所有的内容也就这么多了。
1.定义一个字符串数组并初始化,然后输出其中的字符串. #include <iostream> using namespace std;int main(){ char str[]=&qu ...
- subprocess学习
转自http://blog.csdn.net/imzoer/article/details/8678029 subprocess的目的就是启动一个新的进程并且与之通信. subprocess模块中只定 ...
- Redis(三)、Redis主从复制
一.主从复制 主从复制:主节点负责写数据,从节点负责读数据,从而实现读写分离,提高redis的高可用性. 让一个服务器去复制(replicate)另一个服务器,我们称呼被复制的服务器为主节点(mast ...
- 【MFC】虚拟键代码
一:首先介绍键盘消息 系统消息: ALT,F1,——F24等,是由系统内部处理的,程序本身就存在,比如F1是帮助键. WM_SYSKEYDOWN WM_SYSKEYUP WM_SYSCHAR 非系统消 ...
- 还是UVa340
#include<stdio.h> #define maxn 1010 int main() { int num,a[maxn],i,j,b[maxn]; ; &&num) ...
- Virtualbox guest in KDE Neon
在最新版的KDE Neon里面装VirtualBox客户端工具,折腾了好久,时间紧的时候不得已用共享U盘的方法将就. 之前要么装完关机按钮点了没反应,要么重启进桌面后任务栏消失,再就是进去之后复制东西 ...
- Mac 查看 剪贴板/剪切板/粘贴板 内容与格式
命令行形式 osascript -e 'clipboard info' GUI 形式 Finder->编辑->显示剪贴板 图示:
- 常用 CSS 选择器
// css 读取顺序从右到左,符合要求的都会匹配 // 通配符选择器 -- 选择所有元素 * // 通配符选择器 -- 选择某个元素下的所有元素 .demo * // 元素选择器 html,body ...
- openlayers5学习笔记-001
tmp.initPoint = function (items) { //初始化所有农户点坐标,聚合 var count = items.length; var features = new Arra ...
- 树(6)-----DFS
1.二叉树的反向层次遍历 def levelOrderBottom1(self, root): res = [] self.dfs(root, 0, res) return res def dfs(s ...