对于关键路径的详细介绍看王道P234页,对于里面事件最早/最晚发生时间,活动的最早/最晚开始时间的概念要清晰,计算要清晰,能够手动模拟关键路径的计算
算法//使用邻接表来创建AOE网 int CreatUN_AOE(ALGraph* G){ ArcNode* r[MAX_VERTEX_NUM]; //用作访问标记,用来定位 ArcNode* p; //需要插入的结点 printf("Please input the num of vex and arc:"); scanf("%d,%d",&(G->vexnum),&(G->arcnum)); getchar(); //初始化数据 printf("Please input the data of vex:n"); for (int i = 0; i < G->vexnum; ++i) { scanf("%d",&(G->vertices[i].data)); getchar(); G->vertices[i].firstarc = NULL; r[i] = NULL; } int v1,v2,info; //读取各边,开始制作邻接表 for (int i = 0; i < G->arcnum; ++i) { printf("Please input the trail , head and info:"); scanf("%d,%d,%d",&v1,&v2,&info); getchar(); //这里的头和尾指的是,弧头的顶点和弧尾的顶点 int trail = LocateVex_AL(*G,v1); int head = LocateVex_AL(*G,v2); //判断图中是否含有顶点 if (head==-1||trail==-1){ return 0; } //制作结点 p = (ArcNode*)malloc(sizeof (ArcNode)); if (!p){ exit(0); //分配内存失败 } p->adjvex = head; p->info = info; p->nextarc = NULL; if (r[trail] == NULL){ G->vertices[trail].firstarc = p; } else{ r[trail]->nextarc = p; } r[trail] = p; } return 1; } void OutPutAllGraph_AOE(ALGraph G){ ArcNode* p; for (int i = 0; i < G.vexnum; ++i) { printf("%d->",G.vertices[i].data); p = G.vertices[i].firstarc; while (p){ printf("%d|%dt",p->adjvex,p->info); p = p->nextarc; } printf("n"); } } //初始化栈 *** 作 #define MaxSize 50 //定义栈的深度 typedef struct { int data[MaxSize]; //栈数组 int top; //栈头 }SqStack; //初始化 void InitStack(SqStack* S){ S->top = -1; //初始化栈顶指针 } //判断栈是否为空 bool StackEmpty(SqStack S){ if (S.top == -1){ return true; } else{ return false; } } //进栈 bool Push(SqStack* S,int x){ if (S->top == MaxSize-1){ //栈满 return false; } S->data[++S->top] = x; return true; } //出栈 bool Pop(SqStack* S,int* x){ if (S->top == -1){ return false; //栈空 } *x = S->data[S->top--]; return true; } //读栈顶元素 bool GetTop(SqStack S,int* x){ if (S.top == -1){ return false; } *x = S.data[S.top]; return true; } //获取所有结点的入度情况 void FindInDegree(ALGraph G,int indegree[MAX_VERTEX_NUM]){ ArcNode* p; for (int i = 0; i < G.vexnum; ++i) { indegree[i] = 0; //初始化数组全部为0 } //遍历邻接表,计算所有顶点的入度情况 for (int i = 0; i < G.vexnum; ++i) { p = G.vertices[i].firstarc; //指向当前顶点的第一个连接顶点 while (p){ indegree[p->adjvex]++; //度数加一 p = p->nextarc; } } } //定义全局变量 SqStack T; int ve[MAX_VERTEX_NUM]; //各时间的最早开始时间 int vl[MAX_VERTEX_NUM]; //各时间的最晚开始时间 int TopologicalSort_AOE(ALGraph G){ int indegree[G.vexnum]; //统计顶点的入度 FindInDegree(G,indegree); ArcNode* p; //建立栈结构,用来拓扑排序 SqStack S; InitStack(&S); InitStack(&T); //查找度为0的顶点,并作为将其压入栈中,作为起始点 for (int i = 0; i < G.vexnum; ++i) { if (indegree[i]==0){ Push(&S,i); //压入的时顶点在顶点数组中的下标 } ve[i] = 0; //初始化最早时间 } int count = 0; while (!StackEmpty(S)){ int index; Pop(&S,&index); Push(&T,index); //用来计算最晚开始时间,所以需要先压入栈 count++; //遍历每个结点,获取拓扑排序 for (p = G.vertices[index].firstarc;p;p = p->nextarc) { int k = p->adjvex; //顶点所在的下标 //将顶点的入读减一 indegree[k]--; if (indegree[k]==0){ //入度减一之后如果为0,则押入到栈中 Push(&S,k); } //计算最早开始时间,如果边的源点的最长路径加上边上的权值,必要汇点的最长路径要长,则覆盖ve数组中对应的位置 //那么最终结束的时候,ve数组中存储的就是各顶点的最长路径长度 if (ve[index]+p->info > ve[k]){ ve[k] = ve[index]+p->info; } } } if (count < G.vexnum){ return false; //证明有环 } else{ return true; } } void CriticalPath(ALGraph G){ //如果拓扑排序失败则证明有环 if (!TopologicalSort_AOE(G)){ return; } //初始化最晚开始时间 for (int i = 0; i < G.vexnum; ++i) { vl[i] = ve[G.vexnum-1]; //使最晚开始时间全部为最中汇点的最早开始时间 } //生成事件最晚发生时间 int start,end; //start表示起始点,end表示指向点 ArcNode* p; while (!StackEmpty(T)){ Pop(&T,&start); for (p = G.vertices[start].firstarc;p;p=p->nextarc) { end = p->adjvex; //start点指向的点 //出事情况下,vl数组中每个单元都是整个图的最终汇点的ve,如果每个边的汇点减去边的权值比源点小,就保存小的 if (vl[end]-p->info < vl[start]){ vl[start] = vl[end] - p->info; } } } //循环求各边的最早开时间和最晚开始时间 int k; for (int i = 0; i < G.vexnum; ++i) { for (ArcNode* t = G.vertices[i].firstarc;t;t=t->nextarc) { k = t->adjvex; //各活动的最早开时间与各顶点的最早开始时间一样 int e = ve[i]; //各活动的最晚开始时间等于各顶点的最晚开始时间减去权值 int l = vl[k] - t->info; //判断是否相等,若相等则表明为关键活动,用*表示 char tag = (e==l)?'*':' '; //分别表示线段的起始点,终点,边上的权值,边上活动的最早开始时间,最晚开始时间,是否是关键活动 printf("%d %d %d %d %d %cn",G.vertices[i].data,G.vertices[k].data,t->info,e,l,tag); } } }
使用邻接表来表示图
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)