图的关键路径

  在经过两天的奋斗后,总算是把算法给实现了。说实话,这个并不是我个人原创。而是,在看过很多前辈的思路后,一步一步踏着他们的脚印前进。当然,在这一过程中,我也遇到了不少小麻烦,毕竟再怎么模仿,离别人的想法总是有点差距。不过,也正是由于这些小麻烦,让我对于整体的理解愈发深入。最后,再感谢一下各位前辈!以下就是我的代码:(如果有错误的地方,还望大家指点一下)

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;  
    }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值