拓扑排序的应用

来源:互联网 发布:南昌市金域名都二手房 编辑:程序博客网 时间:2024/05/22 00:50
/*adjlist.h有向无环图的邻接表存储结构*/
#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAX_VERTEX_NUM 10#define MAX_NAME 10typedef char VertexData[MAX_NAME];typedef struct ArcNode{int adjvex;int weight;struct ArcNode *nextarc;}ArcNode;typedef struct VertexNode{VertexData data;ArcNode *firstarc;}VertexNode;typedef struct{VertexNode vertex[MAX_VERTEX_NUM];int vertexnum,arcnum;}AdjList;void Visit(char *s){printf("%s",s);}int LocateVertex(AdjList *G,VertexData u){int i;for(i=0;i<G->vertexnum;i++)if(!strcmp(u,(*G).vertex[i].data))return i;return -1;}void CreateGraph(AdjList *G){int i;int head,tail;VertexData vh,vt;ArcNode *p=NULL,*pnew=NULL;printf("请输入有向无环图的顶点数,边数(以逗号隔开):");scanf("%d,%d",&G->vertexnum,&G->arcnum);for(i=0;i<G->vertexnum;i++){printf("请输入%d个顶点(工程事件): \n",i+1);scanf("%s",(*G).vertex[i].data);(*G).vertex[i].firstarc=NULL;}for(i=0;i<G->arcnum;i++){printf("输入第%d个活动的弧头: ",i+1);scanf("%s",vh);printf("输入第%d个活动的弧尾:",i+1);scanf("%s",vt);head=LocateVertex(G,vh);tail=LocateVertex(G,vt);pnew=(ArcNode *)malloc(sizeof(ArcNode));pnew->adjvex=head;pnew->nextarc=NULL;printf("请输入这个活动的时间: ");scanf("%d",&(pnew->weight));putchar('\n');p=(*G).vertex[tail].firstarc;if(p==NULL)(*G).vertex[tail].firstarc=pnew;else{while(p->nextarc!=NULL)p=p->nextarc;p->nextarc=pnew;}}}
/*stack.h栈的存储结构*/
#define MAX_STACK_NUM MAX_VERTEX_NUM+1typedef struct{int stack[MAX_STACK_NUM];int top;}Stack;void InitStack(Stack *S){S->top=-1;}bool StackEmpty(Stack *S){if(S->top<0)return true;elsereturn false;}bool IsFull(Stack *S){if(S->top>MAX_VERTEX_NUM)return true;elsereturn false;}bool Push(Stack *S,int in){S->top++;if(IsFull(S)){fprintf(stderr,"栈满");return false;}S->stack[S->top]=in;return true;}bool Pop(Stack *S,int *out){if(StackEmpty(S)){fprintf(stderr,"栈空\n");return false;}*out=S->stack[S->top--];return true;}

/*main.c驱动程序*/
#include"adjlist.h"#include"stack.h"int indegree[MAX_VERTEX_NUM];int ve[MAX_VERTEX_NUM];  //各顶点事件的最早发生时间int vl[MAX_VERTEX_NUM];  //各顶点事件的最迟发生时间void FindIndegree(AdjList *G){int i,k;ArcNode *p;for(i=0;i<G->vertexnum;i++)for(p=G->vertex[i].firstarc;p;p=p->nextarc){k=p->adjvex;indegree[k]++;}}bool TopologicalOrder(AdjList *G,Stack *T){int i,j,k;int count=0;//用来对输出的拓扑序列进行计数ArcNode *p=NULL;//用来将每次以出栈顶点为弧尾的弧删除的辅助指针Stack S;//S为0入度顶点栈memset(indegree,0,sizeof(indegree));memset(ve,0,sizeof(ve)); //初始化顶点事件 最早发生时间FindIndegree(G);InitStack(&S);/*接下来让所有入度为0的顶点入栈*/for(i=0;i<G->vertexnum;i++)if(!indegree[i])Push(&S,i);InitStack(T);printf("\n拓扑序列是: ");while(!StackEmpty(&S)){Pop(&S,&j);Push(T,j);++count;   //j号顶点入T栈并计数printf("%s   ",G->vertex[j].data);for(p=G->vertex[j].firstarc;p;p=p->nextarc)    {   k=p->adjvex;   if(!(--indegree[k]))   Push(&S,k);   //若k顶点入度为0则入0度顶点栈S   if(ve[j]+p->weight > ve[k])   ve[k]=ve[j]+p->weight;//这条if语句求以k为弧头的顶点的最早发生时间    }}if(count<G->vertexnum)   //该有向图有回路return false;return true;}bool CriticalPath(AdjList *G){int i,j,k;int dut; //记录活动时间int ee,el;  //ee代表活动的最早开始时间,el代表活动的最迟开始时间ArcNode *p;Stack T; //栈T是拓扑序列栈if(TopologicalOrder(G,&T))printf("\n工程能顺利完工\n");else{printf("\n工程无法顺利完工\n");return false;}for(i=0;i<G->vertexnum;i++)//初始化顶点事件 最迟发生时间vl[i]=ve[G->vertexnum-1];/*接下来按拓扑逆序求个顶点的vl值*/while(!StackEmpty(&T)){Pop(&T,&j);for(p=G->vertex[j].firstarc;p;p=p->nextarc){k=p->adjvex;dut=p->weight;if(vl[k] - dut < vl[j])vl[j]=vl[k] -dut;}}  /*到此处为止已经求出了给个顶点的ve和vl值了最后要求关键活动只要     比较弧的ee和el值如果相等就代表该弧所代表的就是关键活动*/printf("该工程的关键活动是:\n");for(i=0;i<G->vertexnum;i++)for(p=G->vertex[i].firstarc;p;p=p->nextarc){k=p->adjvex;dut=p->weight;ee=ve[i];el=vl[k]-dut;if(ee==el)printf("\t从%s到%s所经时间\n",G->vertex[i].data,G->vertex[k].data);}     return true;}int main(void){AdjList G;//freopen("text.txt","r",stdin);CreateGraph(&G);if(CriticalPath(&G))printf("最短工期为%d\n",ve[G.vertexnum-1]);//fclose(stdin);}



0 0
原创粉丝点击