zoukankan      html  css  js  c++  java
  • 图——关键路径(代码超详细注释)

        关键路径是图中一个比较重要的知识点,它的用处也很大,例如可以帮助企业哪些生产步骤是整个生产进度的关键,提高这些生产步骤的效率就能提高整个生产过程的效率。

        关键路径的关键是要了解四个概念,即事件最早发生时间,事件最晚发生时间,活动最早发生时间,活动最晚发生时间。它们的定义如下:

        敲黑板~~

        事件最早发生时间:即顶点的最早发生时间

        事件最晚发生时间:即顶点的最晚发生时间

        活动最早发生时间:活动最早开工时间,即弧的最早发生时间

       活动最晚发生时间:活动在不推迟工期的前提下的最晚发生时间,即弧的最晚发生时间


     理解了这四个概念,接下来就一片明朗了,

    首先用拓扑排序记录下各个事件的发生顺序(用栈),并依次计算出事件的最早发生时间。

    然后依次出栈,从汇点倒推回各个事件的最晚发生时间。

    最后,再计算出活动最早发生时间(活动最早发生时间与弧头顶点的最早发生时间相同),以及活动最晚发生时间(活动最迟发生时间等于弧尾顶点的最晚发生时间减去边的权重)。大功告成!

    上代码,超详细注释哦~~~~~~~~~~

     测试用的图,图的储存结构采用邻接表式,各个边表结点还储存有边的权重。

    /*------------------------------------
    *		关键路径的代码实现
    *------------------------------------*/
    
    #include <iostream>
    
    using namespace std;
    
    #define USED 1
    #define UNUSED 0
    #define OK 1
    #define ERROR 0
    #define MAXSIZE 64
    
    typedef short Status;//返回状态
    
    int *etv,*ltv;//事件最早和最晚发生时间
    int *Stack2;//用于存储拓扑序列的栈,在最后推事件最晚时间的时用
    int top2;
    
    //邻接表的一些声明
    //边表结点声明
    typedef struct EdgeNode
    {
    	int adjVex;//记录该边对应的顶点的下标
    	int weight;//记录边,即活动的权重
    	struct EdgeNode *next;//指向下一条边
    }EdgeNode;
    
    //顶点结点的声明
    typedef struct VertexNode
    {
    	int in;//记录入度
    	int data;//记录信息
    	EdgeNode *firstEdge;//记录顶点指向的第一条边
    }VertexNode,AdjList[MAXSIZE];
    
    typedef struct Graph
    {
    	AdjList adjList;//顶点信息
    	int numVertexes,numEdges;//图的顶点数和边数
    }GraphAdjList,*pGraphAdjList;
    
    //拓扑排序计算出事件最早的发生时间
    Status TopologicalSort(GraphAdjList g)
    {
    	int i,j;//无名小卒
    	int count = 0;//记录下总共读取有多少顶点,用于判断是否有环路
    
    	int *Stack;//临时栈
    	int top = 0;//Stack栈顶指针
    
    	Stack = new int[MAXSIZE];//分配空间
    	etv = new int[MAXSIZE];//为事件最早发生时间分配空间
    	Stack2 = new int[MAXSIZE];//记录最后拓扑排序的顺序
    	top2 = 0;//Stack2的栈顶指针
    
    	//初始化事件最早发生时间为0
    	for (i = 0;i<MAXSIZE;i++)
    	{
    		etv[i] = 0;
    	}
    	for (i = 0;i<g.numVertexes;i++)
    	{
    		if (0 == g.adjList[i].in)
    		{
    			Stack[++top] = i;//第一个入度为0的顶点入栈,栈中下标为0的位置不使用
    			count++;//读取数目加一
    		}
    	}
    	
    	EdgeNode *e;//边表结点
    	//当Stack栈不为空时
    	while (top != 0)
    	{
    		//Stack栈中的顶点出栈,进入Stack2,并开始读取这个顶点连接的的顶点,使它们的入度减一
    		Stack2[++top2] = Stack[top--];
    		e = g.adjList[Stack2[top2]].firstEdge;
    
    		//将与入度为0的顶点相连的顶点的入度减一
    		for ( ;e!=NULL;e = e->next)
    		{
    			//计算事件最早发生时间,取最大值
    			if(etv[Stack2[top2]]+e->weight>etv[e->adjVex])
    			{
    				etv[e->adjVex] = etv[Stack2[top2]]+e->weight;
    			}
    
    			if (--g.adjList[e->adjVex].in == 0)
    			{
    				Stack[++top] = e->adjVex;//如果入度为0,则进栈
    				count ++;
    			}
    		}
    	}
    	//最后判断是否有环路
    	if(count == g.numVertexes)
    	{
    		return OK;
    	}
    	else
    	{
    		return ERROR;
    	}
    }
    
    //计算关键路径的函数,从汇点出发倒推回事件最晚发生时间
    void CriticalPath(GraphAdjList g)
    {
    	int i,j,k;//无名小卒
    
    	TopologicalSort(g);//先进行拓扑排序
    	ltv  = new int[MAXSIZE];//为事件最晚发生时间分配空间
    	//初始化事件最晚发生时间为最终所需的时间
    	for (i = 0;i<g.numVertexes;i++)
    	{
    		ltv[i] = etv[g.numVertexes-1];
    	}
    
    	//别忘了,栈中的0号下标我们是不用滴
    	int getTop;//获取栈顶元素
    	EdgeNode *e;//边表元素
    	while(top2!=0)
    	{
    		getTop = Stack2[top2--];//出栈
    		for (e = g.adjList[getTop].firstEdge;e!=NULL;e = e->next)
    		{
    			//计算事件最晚发生时间,从汇点出发倒推每个事件的最晚发生时间
    			if (ltv[e->adjVex]-e->weight<ltv[getTop])
    			{
    				ltv[getTop] = ltv[e->adjVex]-e->weight;
    			}
    		}
    	}
    	//打印关键路径
    	int ete,lte;//活动最早和最晚发生时间
    	//这里解释一下为什么要小于g.numVertexes-1,应为g.numVertexes-1已经为最后一个点,它不可能还有下一点
    	for (i = 0;i<g.numVertexes-1;i = e->adjVex)
    	{
    		for (e = g.adjList[i].firstEdge;e!=NULL;e = e->next)
    		{
    			ete = etv[i];//活动最早发生时间与弧头顶点的最早发生时间相同
    			lte = ltv[e->adjVex]-e->weight;//活动最迟发生时间等于弧尾顶点的最晚发生时间减去边的权重
    
    			//如果活动最早发生时间与活动最晚发生时间相等,说明是关键路径中的一部分
    			static int count;
    			if(ete == lte)
    			{
    				cout.width(3);
    				cout.fill('0');
    				cout <<++count<<":"<<g.adjList[i].data<<"->"<<g.adjList[e->adjVex].data<<endl;//打印
    				break;
    			}
    		}
    	}
    
    }
    
    int main()
    {
    	int i,j,k;//无名小卒
    	//测试数据
    	GraphAdjList GL;
    	GL.numVertexes = 10;//顶点数
    	GL.numEdges = 13;//边数
    	EdgeNode *e;
    	EdgeNode *e1;
    
    	e = new EdgeNode;
    	e1 = new EdgeNode;
    	e->adjVex = 2;
    	e->weight = 4;
    	e1->adjVex= 1;
    	e1->weight= 3;
    	e1->next = NULL;
    	e ->next = e1;
    	GL.adjList[0].firstEdge = e;
    	GL.adjList[0].data = 0;
    	GL.adjList[0].in = 0;
    
    	e = new EdgeNode;
    	e1 = new EdgeNode;
    	e->adjVex = 4;
    	e->weight = 6;
    	e1->adjVex= 3;
    	e1->weight= 5;
    	e1->next = NULL;
    	e ->next = e1;
    	GL.adjList[1].firstEdge = e;
    	GL.adjList[1].data = 1;
    	GL.adjList[1].in = 1;
    
    	e = new EdgeNode;
    	e1 = new EdgeNode;
    	e->adjVex = 5;
    	e->weight = 7;
    	e1->adjVex= 3;
    	e1->weight= 8;
    	e1->next = NULL;
    	e ->next = e1;
    	GL.adjList[2].firstEdge = e;
    	GL.adjList[2].data = 2;
    	GL.adjList[2].in = 1;
    
    	e = new EdgeNode;
    	e->adjVex = 4;
    	e->weight = 3;
    	e->next = NULL;
    	GL.adjList[3].firstEdge = e;
    	GL.adjList[3].data = 3;
    	GL.adjList[3].in = 2;
    
    	e = new EdgeNode;
    	e1 = new EdgeNode;
    	e->adjVex = 7;
    	e->weight = 4;
    	e1->adjVex= 6;
    	e1->weight= 9;
    	e1->next = NULL;
    	e ->next = e1;
    	GL.adjList[4].firstEdge = e;
    	GL.adjList[4].data = 4;
    	GL.adjList[4].in = 2;
    
    	e = new EdgeNode;
    	e->adjVex = 7;
    	e->weight = 6;
    	e->next = NULL;
    	GL.adjList[5].firstEdge = e;
    	GL.adjList[5].data = 5;
    	GL.adjList[5].in = 1;
    
    	e = new EdgeNode;
    	e->adjVex = 9;
    	e->weight = 2;
    	e->next = NULL;
    	GL.adjList[6].firstEdge = e;
    	GL.adjList[6].data = 6;
    	GL.adjList[6].in = 1;
    
    	e = new EdgeNode;
    	e->adjVex = 8;
    	e->weight = 5;
    	e->next = NULL;
    	GL.adjList[7].firstEdge = e;
    	GL.adjList[7].data = 7;
    	GL.adjList[7].in = 2;
    	
    	e = new EdgeNode;
    	e->adjVex = 9;
    	e->weight = 3;
    	e->next = NULL;
    	GL.adjList[8].firstEdge = e;
    	GL.adjList[8].data = 8;
    	GL.adjList[8].in = 1;
    
    	GL.adjList[9].firstEdge = NULL;
    	GL.adjList[9].data = 9;
    	GL.adjList[9].in = 2;
    	//以上构建了一个图,不用管
    
    	CriticalPath(GL);
    
    	system("pause");
    	return 0;
    }


  • 相关阅读:
    关于python列表中的赋值问题
    $' ': command not found报错问题
    0day安全-软件漏洞分析技术(第二版)——Crack实验一
    PNI12927 学习笔记
    Mini2440串口通信之DMA
    Mini2440串口通信
    Mini2440的外部中断编写
    VM中设置redhat为静态IP
    ldr指令小记
    Makefile文件编写小记
  • 原文地址:https://www.cnblogs.com/sj2050/p/13413722.html
Copyright © 2011-2022 走看看