拓扑排序和关键路径课程设计

目录

1.    设计任务书... 3

1.1设计任务... 3

1.2程序功能... 3

1.3运行环境... 3

2.    本组课题... 3

2.1课题... 3

2.2本人任务... 3

3.程序功能简介... 4

3.1拓扑排序算法分析... 4

3.2关键路径算法分析... 4

4.功能实现分析... 5

4.1拓扑排序功能... 5

4.1.1具体实例... 5

4.1.2程序流程图... 6

4.1.3关键代码... 6

4.2关键路径功能... 7

4.2.1具体实例... 7

4.2.2程序流程图... 8

4.2.3关键代码... 8

4.3设计过程浅谈... 10

4.4源代码... 11

4.4.1拓扑排序... 11

4.4.2拓扑排序程序运行截图... 18

4.4.3关键路径... 18

4.4.4关键路径程序运行截图... 25

  1. 设计任务书

1.1设计任务

  阅读了《数据结构(C语言)》的经典著作后,学习了有关简单算法的实现,认识到数学可

以应用到各个领域。本次算法课程设计运用所学的图论的拓扑排序和关键路径,去实现工程中的花费时间和顺利进行问题。拓扑排序主要用于检验工程能否施工,关键路径主要用于看出工程施工时间消耗。

1.2程序功能

  本程序可以对给定输入的图进行拓扑排序以及利用拓扑排序的到的序列进行关键路径的求解,程序采用C语言代码实现,用到链表、图论等相关知识构成。

1.3运行环境

  运行系统:Windows 10、Centos 7;

  运行环境:C;

  编译环境:CodeBlocks、Sublime Text 3;

  1. 本组课题

2.1课题

编写数据结构广泛使用拓扑排序和关键路径算法。

2.2本人任务

使用代码实现拓扑排序,进而利用拓扑排序得到的序列球的关键路径。

3.程序功能简介

3.1拓扑排序算法分析

用顶点表示活动,用弧表示活动间的优先关系的有向图为AOV网。

AOV网中没有环,检测的办法是进行拓扑排序。

步骤:

(1)在有向图中选一个没有前驱的顶点且输出之。

(2)从图中删除该顶点和所有以它为尾的弧。

重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。另一种情况则说明有向图中存在环。

3.2关键路径算法分析

与AOV网对应的是AOE网,即用边表示活动的网,AOE网是一个带权的有向无环图,顶点表示事件,弧表示活动,权表示活动持续的时间。通常用AOE网估计工程的完成时间。

由于在AOE网中有些活动可以并行的进行,所以完成工程的最短时间是从开始点到完成点的最长路径的长度。路径最长的叫关键路径,我们用e(i)表示活动最早开始时间,l(i)表示最迟开始时间。两者之差l(i)一e(i)意味着完成活动a的时间余量。我们把l(i)=e(i)的活动叫做关键活动。显然;关键路径上的所有活动都是关键活动,因此提前完成非关键活动并不能加快工程的进度。

4.功能实现分析

4.1拓扑排序功能

4.1.1具体实例

1

4

6

2

3

5

3

4

2

5

2

5

5

1

4

6

1

2

4

3

5

             实例所示为拓扑排序过程。

             最终得到的拓扑序列:V1-V6-V4-V3-V2-V5

图的基本操作

4.1.2程序流程图

图的邻接存储

TopologicalSort(ALGraph G)

得到拓扑序列

                                                                                                                                         

4.1.3关键代码                                                                         

Status TopologicalSort(ALGraph G)

 { /* 有向图G采用邻接表存储结构。若G无回路,则输出G的顶点的一个拓扑序列并返回OK, */

   /* 否则返回ERROR。算法7.12 */

   int i,k,count,indegree[MAX_VERTEX_NUM];

   SqStack S;

   ArcNode *p;

   FindInDegree(G,indegree); /* 对各顶点求入度indegree[0..vernum-1] */

   InitStack(&S); /* 初始化栈 */

   for(i=0;i<G.vexnum;++i) /* 建零入度顶点栈S */

     if(!indegree[i])

       Push(&S,i); /* 入度为0者进栈 */

   count=0; /* 对输出顶点计数 */

   while(!StackEmpty(S))

   { /* 栈不空 */

     Pop(&S,&i);

     printf("%s ",G.vertices[i].data); /* 输出i号顶点并计数 */

     ++count;

     for(p=G.vertices[i].firstarc;p;p=p->nextarc)

     { /* 对i号顶点的每个邻接点的入度减1 */

       k=p->adjvex;

       if(!(--indegree[k])) /* 若入度减为0,则入栈 */

         Push(&S,k);

     }

   }

   if(count<G.vexnum)

   {

     printf("此有向图有回路\n");

     return ERROR;

   }

   else

   {

     printf("为一个拓扑序列。\n");

     return OK;

   }

 }

4.2关键路径功能

4.2.1具体实例

栈操作

图的邻接表

4.2.2程序流程图

图的基本操作

广度优先遍历

StatusTopologicalSort(ALGraph G)

求得关键路径

队列操作

拓扑排序

4.2.3关键代码

Status TopologicalOrder(ALGraph G,SqStack *T)

 { /* 算法7.13  有向网G采用邻接表存储结构,求各顶点事件的最早发生时间ve */

   /* (全局变量)。T为拓扑序列顶点栈,S为零入度顶点栈。若G无回路,则用栈T */

   /* 返回G的一个拓扑序列,且函数值为OK,否则为ERROR */

   int j,k,count,indegree[MAX_VERTEX_NUM];

   SqStack S;

   ArcNode *p;

   FindInDegree(G,indegree);/*对各顶点求入度indegree[0..vernum-1] */

   InitStack(&S); /* 初始化栈 */

   for(j=0;j<G.vexnum;++j) /* 建零入度顶点栈S */

     if(!indegree[j])

       Push(&S,j); /* 入度为0者进栈 */

   InitStack(T); /* 初始化拓扑序列顶点栈 */

   count=0; /* 对输出顶点计数 */

   for(j=0;j<G.vexnum;++j) /* 初始化ve[]=0 (最小值) */

     ve[j]=0;

   while(!StackEmpty(S))

   { /* 栈不空 */

     Pop(&S,&j);

     Push(T,j); /* j号顶点入T栈并计数 */

     ++count;

     for(p=G.vertices[j].firstarc;p;p=p->nextarc)

     { /* 对j号顶点的每个邻接点的入度减1 */

       k=p->adjvex;

       if(--indegree[k]==0) /* 若入度减为0,则入栈 */

         Push(&S,k);

       if(ve[j]+*(p->info)>ve[k])

         ve[k]=ve[j]+*(p->info);

     }

   }

   if(count<G.vexnum)

   {

     printf("此有向网有回路\n");

     return ERROR;

   }

   else

     return OK;

 }

 Status CriticalPath(ALGraph G)

 { /* 算法7.14 G为有向网,输出G的各项关键活动 */

   int vl[MAX_VERTEX_NUM];

   SqStack T;

   int i,j,k,ee,el;

   ArcNode *p;

   char dut,tag;

   if(!TopologicalOrder(G,&T)) /* 产生有向环 */

     return ERROR;

   j=ve[0];

   for(i=1;i<G.vexnum;i++) /* j=Max(ve[]) 完成点的值 */

     if(ve[i]>j)

       j=ve[i];

   for(i=0;i<G.vexnum;i++) /* 初始化顶点事件的最迟发生时间(最大值) */

     vl[i]=j; /* 完成点的最早发生时间 */

   while(!StackEmpty(T)) /* 按拓扑逆序求各顶点的vl值 */

     for(Pop(&T,&j),p=G.vertices[j].firstarc;p;p=p->nextarc)

     {

       k=p->adjvex;

       dut=*(p->info); /* dut<j,k> */

       if(vl[k]-dut<vl[j])

         vl[j]=vl[k]-dut;

     }

   printf(" j  k  dut  ee  el  tag\n");

   for(j=0;j<G.vexnum;++j) /* 求ee,el和关键活动 */

     for(p=G.vertices[j].firstarc;p;p=p->nextarc)

     {

       k=p->adjvex;

       dut=*(p->info);

       ee=ve[j];

       el=vl[k]-dut;

       tag=(ee==el)?'*':' ';

       printf("%2d %2d %3d %3d %3d    %c\n",j,k,dut,ee,el,tag); /* 输出关键活动 */

     }

   printf("关键活动为:\n");

   for(j=0;j<G.vexnum;++j) /* 同上 */

     for(p=G.vertices[j].firstarc;p;p=p->nextarc)

     {

       k=p->adjvex;

       dut=*(p->info);

       if(ve[j]==vl[k]-dut)

         printf("%s→%s\n",G.vertices[j].data,G.vertices[k].data); /* 输出关键活动 */

     }

   return OK;

 }

4.3设计过程浅谈

在大一一学年的时间,初识了C语言和JAVA语言,学习了编程的基本功,认识到技术的道路漫长而遥远,只有不断的通过自学和向别人学习,不断保持进步的节奏。提高人生视野来认识更多的编程方法,去创新。

学习是需要付出时间和精力的,一直有输入才能厚积薄发,在学习数据结构课程时,一开始也是感觉很难,不知道无从下手,曾经纠结迷茫也失去信心。但随着时间的推进,好多困难渐渐克服,发现温故而知新的力量是真的强大。从一开始认识算法的时间复杂度和空间复杂度,进一步认识到线性结构和非线性结构,又从中学习了链表、栈、队列、串,到后来的树和图论。这些东西循序渐进,慢慢的组成了一张自己对于数据结构的知识网络。

“路漫漫其修远兮,吾将上下而求索”是教会我们学无止境,书山有路,勤能补拙大丈夫。

4.4源代码

4.4.1拓扑排序

#include<string.h>

 #include<malloc.h> /* malloc()等 */

 #include<limits.h> /* INT_MAX等 */

 #include<stdio.h> /* EOF(=^Z或F6),NULL */

 #include<stdlib.h> /* atoi() */

 #include<math.h> /* floor(),ceil(),abs() */

 /* 函数结果状态代码 */

 #define TRUE 1

 #define FALSE 0

 #define OK 1

 #define ERROR 0

 #define INFEASIBLE -1

 typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */

 typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */

 #define MAX_NAME 5 /* 顶点字符串的最大长度 */

 typedef int InfoType;

 typedef char VertexType[MAX_NAME]; /* 字符串类型 */

 /* 图的邻接表存储表示 */

 #define MAX_VERTEX_NUM 20

 /*网和图的区别是图没有权值,网有权值*/

 typedef enum{DG,DN,AG,AN}GraphKind; /*  用枚举类型建立图的种类 {有向图,有向网,无向图,无向网} */

 typedef struct ArcNode

 {

   int adjvex; /* 该弧所指向的顶点的位置 */

   struct ArcNode *nextarc; /* 指向下一条弧的指针 */

   InfoType *info; /* 网的权值指针) */

 }ArcNode; /* 表结点 */

 typedef struct

 {

   VertexType data; /* 顶点信息 */

   ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */

 }VNode,AdjList[MAX_VERTEX_NUM]; /* 头结点 */

 typedef struct

 {

   AdjList vertices;

   int vexnum,arcnum; /* 图的当前顶点数和弧数 */

   int kind; /* 图的种类标志 */

 }ALGraph;

 /* 图的邻接表存储的基本操作(15个) */

 int LocateVex(ALGraph G,VertexType u)

 { /* 初始条件: 图G存在,u和G中顶点有相同特征 */

   /* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */

   int i;

   for(i=0;i<G.vexnum;++i)

     if(strcmp(u,G.vertices[i].data)==0)    //比较顶点是否相等

       return i;

   return -1;

 }

 Status CreateGraph(ALGraph *G)

 { /* 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图) */

   int i,j,k;

   int w; /* 权值 */

   VertexType va,vb;

   ArcNode *p;

   printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");

   scanf("%d",&(*G).kind);

   printf("请输入图的顶点数,边数: ");

   scanf("%d,%d",&(*G).vexnum,&(*G).arcnum);

   printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);

   for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */

   {

     scanf("%s",(*G).vertices[i].data);

     (*G).vertices[i].firstarc=NULL;

   }

   if((*G).kind==1||(*G).kind==3) /* 网 */

     printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");

   else /* 图 */

     printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");

   for(k=0;k<(*G).arcnum;++k) /* 构造表结点链表 */

   {

     if((*G).kind==1||(*G).kind==3) /* 网 */

       scanf("%d%s%s",&w,va,vb);

     else /* 图 */

       scanf("%s%s",va,vb);

     i=LocateVex(*G,va); /* 弧尾 */

     j=LocateVex(*G,vb); /* 弧头 */

     p=(ArcNode*)malloc(sizeof(ArcNode));

     p->adjvex=j;

     if((*G).kind==1||(*G).kind==3) /* 网 */

     {

       p->info=(int *)malloc(sizeof(int));

       *(p->info)=w;                         //网的权值指针

     }

     else

       p->info=NULL; /* 图 */

     p->nextarc=(*G).vertices[i].firstarc; /* 插在表头 */

     (*G).vertices[i].firstarc=p;

     if((*G).kind>=2) /* 无向图或网,产生第二个表结点 */

     {

       p=(ArcNode*)malloc(sizeof(ArcNode));

       p->adjvex=i;

       if((*G).kind==3) /* 无向网 */

       {

         p->info=(int*)malloc(sizeof(int));

         *(p->info)=w;

       }

       else

         p->info=NULL; /* 无向图 */

       p->nextarc=(*G).vertices[j].firstarc; /* 插在表头 */

       (*G).vertices[j].firstarc=p;

     }

   }

   return OK;

 }

 void Display(ALGraph G)

 { /* 输出图的邻接矩阵G */

   int i;

   ArcNode *p;

   switch(G.kind)

   {

     case DG: printf("有向图\n");

              break;

     case DN: printf("有向网\n");

              break;

     case AG: printf("无向图\n");

              break;

     case AN: printf("无向网\n");

   }

   printf("%d个顶点:\n",G.vexnum);

   for(i=0;i<G.vexnum;++i)

     printf("%s ",G.vertices[i].data);

   printf("\n%d条弧(边):\n",G.arcnum);

   for(i=0;i<G.vexnum;i++)

   {

     p=G.vertices[i].firstarc;

     while(p)

     {

       if(G.kind<=1) /* 有向 */

       {

         printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data);

         if(G.kind==DN) /* 网 */

           printf(":%d ",*(p->info));

       }

       else /* 无向(避免输出两次) */

       {

         if(i<p->adjvex)

         {

           printf("%s-%s ",G.vertices[i].data,G.vertices[p->adjvex].data);

           if(G.kind==AN) /* 网 */

             printf(":%d ",*(p->info));

         }

       }

       p=p->nextarc;

     }

     printf("\n");

   }

 }

 void FindInDegree(ALGraph G,int indegree[])

 { /* 求顶点的入度,算法7.12、7.13调用 */

   int i;

   ArcNode *p;

   for(i=0;i<G.vexnum;i++)

     indegree[i]=0; /* 赋初值 */

   for(i=0;i<G.vexnum;i++)

   {

     p=G.vertices[i].firstarc;

     while(p)

     {

       indegree[p->adjvex]++;

       p=p->nextarc;

     }

   }

 }

 typedef int SElemType; /* 栈类型 */

 #define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */

 #define STACKINCREMENT 2 /* 存储空间分配增量 */

 typedef struct SqStack

 {

   SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */

   SElemType *top; /* 栈顶指针 */

   int stacksize; /* 当前已分配的存储空间,以元素为单位 */

 }SqStack; /* 顺序栈 */

   /*  顺序栈的基本操作(9个) */

 Status InitStack(SqStack *S)

 { /* 构造一个空栈S */

   (*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));

   if(!(*S).base)

     exit(OVERFLOW); /* 存储分配失败 */

   (*S).top=(*S).base;

   (*S).stacksize=STACK_INIT_SIZE;

   return OK;

 }

 Status DestroyStack(SqStack *S)

 { /* 销毁栈S,S不再存在 */

   free((*S).base);

   (*S).base=NULL;

   (*S).top=NULL;

   (*S).stacksize=0;

   return OK;

 }

 Status ClearStack(SqStack *S)

 { /* 把S置为空栈 */

   (*S).top=(*S).base;

   return OK;

 }

 Status StackEmpty(SqStack S)

 { /* 若栈S为空栈,则返回TRUE,否则返回FALSE */

   if(S.top==S.base)

     return TRUE;

   else

     return FALSE;

 }

 int StackLength(SqStack S)

 { /* 返回S的元素个数,即栈的长度 */

   return S.top-S.base;

 }

 Status GetTop(SqStack S,SElemType *e)

 { /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */

   if(S.top>S.base)

   {

     *e=*(S.top-1);

     return OK;

   }

   else

     return ERROR;

 }

 Status Push(SqStack *S,SElemType e)

 { /* 插入元素e为新的栈顶元素 */

   if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */

   {

     (*S).base=(SElemType *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));

     if(!(*S).base)

       exit(OVERFLOW); /* 存储分配失败 */

     (*S).top=(*S).base+(*S).stacksize;

     (*S).stacksize+=STACKINCREMENT;

   }

   *((*S).top)++=e;

   return OK;

 }

 Status Pop(SqStack *S,SElemType *e)

 { /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */

   if((*S).top==(*S).base)

     return ERROR;

   *e=*--(*S).top;

   return OK;

 }

 Status StackTraverse(SqStack S,Status(*visit)(SElemType))

 { /* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */

   /* 一旦visit()失败,则操作失败 */

   while(S.top>S.base)

     visit(*S.base++);

   printf("\n");

   return OK;

 }

 Status TopologicalSort(ALGraph G)

 { /* 有向图G采用邻接表存储结构。若G无回路,则输出G的顶点的一个拓扑序列并返回OK, */

   /* 否则返回ERROR。算法7.12 */

   int i,k,count,indegree[MAX_VERTEX_NUM];

   SqStack S;

   ArcNode *p;

   FindInDegree(G,indegree); /* 对各顶点求入度indegree[0..vernum-1] */

   InitStack(&S); /* 初始化栈 */

   for(i=0;i<G.vexnum;++i) /* 建零入度顶点栈S */

     if(!indegree[i])

       Push(&S,i); /* 入度为0者进栈 */

   count=0; /* 对输出顶点计数 */

   printf("(");

   while(!StackEmpty(S))

   { /* 栈不空 */

     Pop(&S,&i);

     printf("%s ",G.vertices[i].data); /* 输出i号顶点并计数 */

     ++count;

     for(p=G.vertices[i].firstarc;p;p=p->nextarc)

     { /* 对i号顶点的每个邻接点的入度减1 */

       k=p->adjvex;

       if(!(--indegree[k])) /* 若入度减为0,则入栈 */

         Push(&S,k);

     }

   }

   printf(")");

   if(count<G.vexnum)

   {

     printf("此有向图有回路\n");

     return ERROR;

   }

   else

   {

     printf("为一个拓扑序列。\n");

     return OK;

   }

 }

 void main()

 {

   ALGraph f;

   printf("请选择有向图\n");

   CreateGraph(&f);

   Display(f);

   TopologicalSort(f);

 }

4.4.2拓扑排序程序运行截图

4.4.3关键路径

void Display(ALGraph G)

 { /* 输出图的邻接矩阵G */

   int i;

   ArcNode *p;

   switch(G.kind)

   {

     case DG: printf("有向图\n");

              break;

     case DN: printf("有向网\n");

              break;

     case AG: printf("无向图\n");

              break;

     case AN: printf("无向网\n");

   }

   printf("%d个顶点:\n",G.vexnum);

   for(i=0;i<G.vexnum;++i)

     printf("%s ",G.vertices[i].data);

   printf("\n%d条弧(边):\n",G.arcnum);

   for(i=0;i<G.vexnum;i++)

   {

     p=G.vertices[i].firstarc;

     while(p)

     {

       if(G.kind<=1) /* 有向 */

       {

         printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data);

         if(G.kind==DN) /* 网 */

           printf(":%d ",*(p->info));

       }

       else /* 无向(避免输出两次) */

       {

         if(i<p->adjvex)

         {

           printf("%s-%s ",G.vertices[i].data,G.vertices[p->adjvex].data);

           if(G.kind==AN) /* 网 */

             printf(":%d ",*(p->info));

         }

       }

       p=p->nextarc;

     }

     printf("\n");

   }

 }

 int ve[MAX_VERTEX_NUM]; /* 全局变量(用于算法7.13和算法7.14) */

 void FindInDegree(ALGraph G,int indegree[])

 { /* 求顶点的入度,算法7.12、7.13调用 */

   int i;

   ArcNode *p;

   for(i=0;i<G.vexnum;i++)

     indegree[i]=0; /* 赋初值 */

   for(i=0;i<G.vexnum;i++)

   {

     p=G.vertices[i].firstarc;

     while(p)

     {

       indegree[p->adjvex]++;

       p=p->nextarc;

     }

   }

 }

 typedef int SElemType; /* 栈类型 */

 #define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */

 #define STACKINCREMENT 2 /* 存储空间分配增量 */

 typedef struct SqStack

 {

   SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */

   SElemType *top; /* 栈顶指针 */

   int stacksize; /* 当前已分配的存储空间,以元素为单位 */

 }SqStack; /* 顺序栈 */

   /*  顺序栈的基本操作(9个) */

 Status InitStack(SqStack *S)

 { /* 构造一个空栈S */

   (*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));

   if(!(*S).base)

     exit(OVERFLOW); /* 存储分配失败 */

   (*S).top=(*S).base;

   (*S).stacksize=STACK_INIT_SIZE;

   return OK;

 }

 Status DestroyStack(SqStack *S)

 { /* 销毁栈S,S不再存在 */

   free((*S).base);

   (*S).base=NULL;

   (*S).top=NULL;

   (*S).stacksize=0;

   return OK;

 }

 Status ClearStack(SqStack *S)

 { /* 把S置为空栈 */

   (*S).top=(*S).base;

   return OK;

 }

 Status StackEmpty(SqStack S)

 { /* 若栈S为空栈,则返回TRUE,否则返回FALSE */

   if(S.top==S.base)

     return TRUE;

   else

     return FALSE;

 }

 int StackLength(SqStack S)

 { /* 返回S的元素个数,即栈的长度 */

   return S.top-S.base;

 }

 Status GetTop(SqStack S,SElemType *e)

 { /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */

   if(S.top>S.base)

   {

     *e=*(S.top-1);

     return OK;

   }

   else

     return ERROR;

 }

 Status Push(SqStack *S,SElemType e)

 { /* 插入元素e为新的栈顶元素 */

   if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */

   {

     (*S).base=(SElemType *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));

     if(!(*S).base)

       exit(OVERFLOW); /* 存储分配失败 */

     (*S).top=(*S).base+(*S).stacksize;

     (*S).stacksize+=STACKINCREMENT;

   }

   *((*S).top)++=e;

   return OK;

 }

 Status Pop(SqStack *S,SElemType *e)

 { /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */

   if((*S).top==(*S).base)

     return ERROR;

   *e=*--(*S).top;

   return OK;

 }

 Status StackTraverse(SqStack S,Status(*visit)(SElemType))

 { /* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */

   /* 一旦visit()失败,则操作失败 */

   while(S.top>S.base)

     visit(*S.base++);

   printf("\n");

   return OK;

 }

 Status TopologicalOrder(ALGraph G,SqStack *T)

 { /* 算法7.13  有向网G采用邻接表存储结构,求各顶点事件的最早发生时间ve */

   /* (全局变量)。T为拓扑序列顶点栈,S为零入度顶点栈。若G无回路,则用栈T */

   /* 返回G的一个拓扑序列,且函数值为OK,否则为ERROR */

   int j,k,count,indegree[MAX_VERTEX_NUM];

   SqStack S;

   ArcNode *p;

   FindInDegree(G,indegree);/*对各顶点求入度indegree[0..vernum-1] */

   InitStack(&S); /* 初始化栈 */

   for(j=0;j<G.vexnum;++j) /* 建零入度顶点栈S */

     if(!indegree[j])

       Push(&S,j); /* 入度为0者进栈 */

   InitStack(T); /* 初始化拓扑序列顶点栈 */

   count=0; /* 对输出顶点计数 */

   for(j=0;j<G.vexnum;++j) /* 初始化ve[]=0 (最小值) */

     ve[j]=0;

   while(!StackEmpty(S))

   { /* 栈不空 */

     Pop(&S,&j);

     Push(T,j); /* j号顶点入T栈并计数 */

     ++count;

     for(p=G.vertices[j].firstarc;p;p=p->nextarc)

     { /* 对j号顶点的每个邻接点的入度减1 */

       k=p->adjvex;

       if(--indegree[k]==0) /* 若入度减为0,则入栈 */

         Push(&S,k);

       if(ve[j]+*(p->info)>ve[k])

         ve[k]=ve[j]+*(p->info);

     }

   }

   if(count<G.vexnum)

   {

     printf("此有向网有回路\n");

     return ERROR;

   }

   else

     return OK;

 }

 Status CriticalPath(ALGraph G)

 { /* 算法7.14 G为有向网,输出G的各项关键活动 */

   int vl[MAX_VERTEX_NUM];

   SqStack T;

   int i,j,k,ee,el;

   ArcNode *p;

   char dut,tag;

   if(!TopologicalOrder(G,&T)) /* 产生有向环 */

     return ERROR;

   j=ve[0];

   for(i=1;i<G.vexnum;i++) /* j=Max(ve[]) 完成点的值 */

     if(ve[i]>j)

       j=ve[i];

   for(i=0;i<G.vexnum;i++) /* 初始化顶点事件的最迟发生时间(最大值) */

     vl[i]=j; /* 完成点的最早发生时间 */

   while(!StackEmpty(T)) /* 按拓扑逆序求各顶点的vl值 */

     for(Pop(&T,&j),p=G.vertices[j].firstarc;p;p=p->nextarc)

     {

       k=p->adjvex;

       dut=*(p->info); /* dut<j,k> */

       if(vl[k]-dut<vl[j])

         vl[j]=vl[k]-dut;

     }

   printf(" j  k  dut  ee  el  tag\n");

   for(j=0;j<G.vexnum;++j) /* 求ee,el和关键活动 */

     for(p=G.vertices[j].firstarc;p;p=p->nextarc)

     {

       k=p->adjvex;

       dut=*(p->info);

       ee=ve[j];

       el=vl[k]-dut;

       tag=(ee==el)?'*':' ';

       printf("%2d %2d %3d %3d %3d    %c\n",j,k,dut,ee,el,tag); /* 输出关键活动 */

     }

   printf("关键活动为:\n");

   for(j=0;j<G.vexnum;++j) /* 同上 */

     for(p=G.vertices[j].firstarc;p;p=p->nextarc)

     {

       k=p->adjvex;

       dut=*(p->info);

       if(ve[j]==vl[k]-dut)

         printf("%s→%s\n",G.vertices[j].data,G.vertices[k].data); /* 输出关键活动 */

     }

   return OK;

 }

 void main()

 {

   ALGraph h;

   printf("请选择有向网\n");

   CreateGraph(&h);

   Display(h);

   CriticalPath(h);

 }

4.4.4关键路径程序运行截图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/482091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2万字超长干货,MIT人工智能实验室:如何做研究?

来源&#xff1a;人工智能前沿讲习译者&#xff1a;柳泉波 北京师范大学信息学院2000级博士生 当你初入江湖&#xff0c;迷茫不知道该干什么的时候&#xff0c;不妨去模仿前人是如何进行科研的&#xff0c;并从中归纳出最适合自己的道路。为此&#xff0c;我们推出“学术人生”…

重磅!DeepMind新作Gato:一个模型、一套权重通吃600+视觉文本和决策任务!

来源&#xff1a;量子位&#xff08;QbitAI&#xff09;作者&#xff1a;梦晨 鱼羊通用人工智能&#xff0c;还得看DeepMind。这回&#xff0c;只一个模型&#xff0c;使用相同的权重&#xff0c;不仅把看家本领雅达利游戏玩得飞起。和人类聊聊天、看图写话也不在话下。甚至还能…

WEB3.0是营销概念?能否代表科技未来趋势的主流

来源&#xff1a;刘锋科学网博客作者 &#xff1a;刘锋链接地址&#xff1a;https://blog.sciencenet.cn/blog-39263-1339334.html本文是根据微信交流的内容整理形成&#xff0c;算是一个随笔&#xff0c;反映了个人的一些观点&#xff0c;未必正确&#xff0c;仅供参考。根据目…

JDKjavac的配置

Path变量&#xff0c;一定要写绝对路径名&#xff0c;不要写相对路径名&#xff0c;写本地的jdk的bin目录和jdk中jre的bin目录&#xff0c;这个win10做的很好&#xff0c;直接写就可以&#xff0c;用不同的变量代替了一个变量&#xff0c;中间还要加分号的尴尬&#xff0c;中间…

Nature:类脑计算亟需宏大蓝图

来源&#xff1a;集智俱乐部作者&#xff1a;A. Mehonic & A. J. Kenyon翻译&#xff1a;任卡娜 审校&#xff1a;JawDrin 编辑&#xff1a;邓一雪 导语与日俱增的算力需求下&#xff0c;现代计算系统能耗也越来越高&#xff0c;很难作为可持续的平台支持人工智能技术的未来…

Sublime Text 3无法安装Package Control插件的解决

QUESTION:Sublime Text 3无法安装Package Control插件的解决? ANSWER: 为了更准确的定位问题&#xff0c;建议插件在安装前开启控制台&#xff08;快捷键Ctrl~&#xff09;,同时在开启debug模式&#xff0c;这样可以在安装过程中了解哪一步出了问题&#xff0c;然后有针对性…

JAVA:线程总结及多线程实现的两种方法

JAVA&#xff1a;线程总结 目录 目录 JAVA&#xff1a;线程总结 JAVA&#xff1a;线程总结 01_多线程(多线程的引入)(了解) 02_多线程(多线程并行和并发的区别)(了解) 03_多线程(Java程序运行原理和JVM的启动是多线程的吗)(了解) 04_多线程(多线程程序实现的方式1)(掌握…

WEB3.0 能否代表科技未来趋势的主流

来源&#xff1a;刘锋科学网博客作者 &#xff1a;刘锋链接地址&#xff1a;https://blog.sciencenet.cn/blog-39263-1339334.html本文是根据微信交流的内容整理形成&#xff0c;算是一个随笔&#xff0c;反映了个人的一些观点&#xff0c;未必正确&#xff0c;仅供参考。根据目…

网线制作,集线器、交换机、路由器的介绍以及路由器的设置

目录 一. 网线制作 1.1 制作材料 1.2 网线标准 1.3 网线做法 二. 集线器、交换机、路由器介绍 前言 简介 简单来说 三. 路由器的设置 设置1 设置2 设置3 设置4 无线设置 一. 网线制作 1.1 制作材料 网线 …

谷歌AI提出双重策略强化学习框架,帮助机器人安全学习动作技能

来源&#xff1a;AI前线作者&#xff1a;Jimmy&#xff08;Tsung-Yen&#xff09; Yang译者&#xff1a;Sambodhi策划&#xff1a;凌敏深度强化学习在自主解决复杂、高维问题方面的前景&#xff0c;引起了 机器人、游戏 和 自动驾驶汽车 等领域的极大兴趣。但是&#xff0c;要想…

美国发布20项重大科技趋势,将在未来30年改变世界!

来源&#xff1a;DeepTech深科技&#xff08;ID&#xff1a;mit-tr&#xff09;编辑&#xff1a;net百晓生这份报告是美国陆军公布的一份长达35页的《2016-2045年新兴科技趋势报告》。它是美国在过去几年由政府机构、咨询机构、智囊团、科研机构等发表的32份科技趋势相关研究调…

对话式人工智能发展的真正限制是人类的耐心

来源&#xff1a;AI前线 作者&#xff1a;Jiang Chen&#xff0c;Moveworks 机器学习副总裁译者&#xff1a;王强策划&#xff1a;刘燕从 Siri 到 Alexa 再到谷歌助手&#xff0c;今天我们已经被各种人工智能系统包围了。它们的设计目标只有一个&#xff1a;理解我们。我们已经…

Nature子刊:科学家在类脑芯片上实现类似LSTM的功能,能效高1000倍

来源&#xff1a;机器学习研究组订阅格拉茨技术大学的计算机科学家在 Nature 子刊上发表的一篇论文表明&#xff0c;他们找到了一种在神经形态芯片上模拟 LSTM 的方案&#xff0c;可以让类脑神经形态芯片上的 AI 算法能效提高约 1000 倍。随着智能手机的普及&#xff0c;手机游…

重磅!0.2nm路线图来了!详细讲解技术实现!

来源&#xff1a;tomshardware编译&#xff1a;EETOP世界上最先进的半导体研究机构 Imec 最近在比利时安特卫普举行的未来峰会上分享了其亚1nm和晶体管路线图。该路线图让我们大致了解了到 2036 年Imec将在其实验室与台积电、英特尔、三星和 ASML 等行业巨头合作研发的下一个主…

问题即答案-解决棘手问题的突破性方法

来源&#xff1a;混沌巡洋舰 “问题”&#xff08;question&#xff09; 中包含一个非常美妙的词&#xff1a;“ 探索”&#xff08;quest&#xff09;。我太喜欢这个词了。——埃利威塞尔&#xff08;Elie Wiesel&#xff09;有些人常常感觉一些真相事关重大&#xff0c;自己应…

CSS:盒子模型和清除float浮动的三种常用方法

目录 一&#xff1a;浮动产生原因&#xff1a; 二&#xff1a;浮动产生副作用: 三&#xff1a;浮动解决方法&#xff1a; QUESTION:CSS盒子模型清除浮动? ANSWER: 一&#xff1a;浮动产生原因&#xff1a; 一般浮动是什么情况呢&#xff1f;一般是一个盒子里使用了CSS fl…

逼真度超越「AI设计师」DALL·E 2!谷歌大脑推出新的文本生成图像模型Imagen

来源&#xff1a;AI科技评论作者&#xff1a;李梅、王玥编辑&#xff1a;陈彩娴文本生成图像模型界又出新手笔&#xff01;这次的主角是Google Brain推出的 Imagen&#xff0c;再一次突破人类想象力&#xff0c;将文本生成图像的逼真度和语言理解提高到了前所未有的新高度&…

量子技术推动新的传感器热潮

IMPERIAL COLLEGE LONDON/M SQUARED来源&#xff1a;IEEE电气电子工程师想象一下&#xff0c;传感器可以探测思想的磁场、帮助月球车探测月球岩石中的氧气&#xff0c;或者接收来自暗物质的无线电波。正如量子计算机可以从理论上找到经典计算机无法解决的问题的答案一样&#x…

0.2nm路线图来了!详细讲解技术实现!

来源&#xff1a;tomshardware世界上最先进的半导体研究机构 Imec 最近在比利时安特卫普举行的未来峰会上分享了其亚1nm和晶体管路线图。该路线图让我们大致了解了到 2036 年Imec将在其实验室与台积电、英特尔、三星和 ASML 等行业巨头合作研发的下一个主要工艺节点和晶体管架构…

走向认知发展的理性建构理论

Towards a Rational Constructivist Theory of Cognitive Development Fei Xu University of California, Berkeley来源&#xff1a;CreateAMind本文对认知发展理论——理性建构主义进行了综述。这种观点的基本原则如下:(a)初始状态:人类婴儿以一组原型概念的原语开始生命。这些…