在经过两天的奋斗后,总算是把算法给实现了。说实话,这个并不是我个人原创。而是,在看过很多前辈的思路后,一步一步踏着他们的脚印前进。当然,在这一过程中,我也遇到了不少小麻烦,毕竟再怎么模仿,离别人的想法总是有点差距。不过,也正是由于这些小麻烦,让我对于整体的理解愈发深入。最后,再感谢一下各位前辈!以下就是我的代码:(如果有错误的地方,还望大家指点一下)
CriticalPath.cpp
# ifndef CRITICALPATH
# define CRITICALPATH
# define MAXVEX 20
typedef int VerTexType ; //图的顶点数据类型
/*表结点*/
typedef struct edgenode{
int AdjVex; //顶点的编号
int weight; //顶点的权值
struct edgenode * next; //指向下一个顶点
}EdgeNode;
/*头结点*/
typedef struct vertexnode{
VerTexType data; //顶点的信息
int in; //顶点的入度
EdgeNode * FirstEdeg; //指向边集点
}VerTexNode;
/*图的数据结构*/
typedef struct graph{
VerTexNode VerTex[MAXVEX];
int NumVerTex,NumEdge;
}Graph;
void CreateGraph(Graph *G); // 创建图
void TopoLogicalSort(Graph *G); //拓扑排序算法
void CriticalPath(Graph *G); //关键路径算法
#endif CRITICALPATH
CriticalPath.cpp
#include "CriticalPath.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
int *ve , *vl; //事件的最早发生时间、最晚发生时间
int *Stack; //用于存储拓扑序列
//生成图
void CreateGraph(Graph *G)
{
EdgeNode *e = NULL;
cout<<"请输入顶点数目、边的数目"<<endl;
cin>>G->NumVerTex>>G->NumEdge;
for(int i = 0 ; i < G->NumVerTex ; i++ )
{
G->VerTex[i].data = i;
G->VerTex[i].in = 0;
G->VerTex[i].FirstEdeg = NULL;
}
cout<<"输入边<Vi ,Vj>的顶点 i,j 以及边的权值 w \n";
int t , j , w;
for(int k =0 ; k<G->NumEdge ; k++ )
{
cin>>t>>j>>w;
edgenode *NewNode = (edgenode *)malloc(sizeof(edgenode)); //申请一个新的结点
NewNode->AdjVex = j;
NewNode->weight = w;
NewNode->next =G->VerTex[t-1].FirstEdeg;
G->VerTex[t-1].FirstEdeg = NewNode;
G->VerTex[j-1].in++; //顶点 j 的入度加1
}
}
//拓扑排序算法
void TopoLogicalSort(Graph *G)
{
int count = 0; //统计输出的顶点数
int gettop; //去除的顶点下标
int front = -1, rear = -1 ;
Stack = (int *)malloc(sizeof(int) * G->NumVerTex);
for(int i = 0;i< G->NumVerTex;i++)
{
if(!(G->VerTex[i].in)) //将入度为0的顶点存储在Stack栈中
{
Stack[++rear] = i; //注意:这里是从++ rear 即Stack[0]
}
}
ve = (int*)malloc(sizeof(int) * G->NumVerTex);
for(int i = 0;i < G->NumVerTex;++i) ve[i] = 0; //事件最早发生时间初始化为0
while(front != rear) //Stack栈不为空,即还有未处理完的入度为 0 顶点
{
front ++ ;
cout<<Stack[front];
gettop = Stack[front]; //出栈
count++;
for(EdgeNode *e = G->VerTex[gettop].FirstEdeg ; e ; e = e->next) //处理下标为gettop的顶点所连接的顶点
{
int k = e->AdjVex;
if(G->VerTex[k].in) //如果被指向的顶点入度减1为0的话压入Stack栈中
Stack[++rear] = k-1;
if(ve[gettop] + e->weight > ve[k]) //事件最早发生的时间
ve[k] = ve[gettop] + e->weight;
}
}
if(count < G->NumVerTex) //如果顶点没有完全输出
{
printf("\n本程序所建立的图有回路不可计算出关键路径:\n");
system("pause");
exit(1);
}
}
void CriticalPath(Graph *G)
{
int ete,lte; //声明事件最早发生时间和最迟发生时间的变量
TopoLogicalSort(G); //拓扑排序求事件的最早发生时间和拓扑序列Stack2
vl = (int *)malloc(sizeof(EdgeNode) * G->NumVerTex);
for(int i = 0;i < G->NumVerTex;++i) //初始化事件最晚发生时间
{
vl[i] = ve[G->NumVerTex - 1];
}
for(int i = G->NumVerTex-2; i>= 0 ;i--) //注意:这里是G->NumVerTex-2
{
int j = Stack[i];
EdgeNode *e = G->VerTex[j].FirstEdeg ;
while(e)
{
int k = e->AdjVex;
if((vl[k]-e->weight)<vl[j])
{
vl[j] = vl[k]-e->weight;
e=e->next;
}
}
}
for(int i = 0;i < G->NumVerTex;++i)
{
for(EdgeNode *e = G->VerTex[i].FirstEdeg;e;e = e->next)
{
int k = e->AdjVex;
ete = ve[i]; //事件最早发生时间
lte = vl[k] - e->weight; //事件最晚发生时间
if(ete == lte) //相等即在关键路径上
{
printf(" <V%d -> V%d) weight: %d\n",G->VerTex[i].data+1,G->VerTex[k].data+1,e->weight);
}
}
}
}
main.cpp
#include "CriticalPath.h"
int main()
{
Graph G;
CreateGraph(&G);
CriticalPath(&G);
return 0;
}