日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

图——关键路径(代码超详细注释)

發布時間:2023/12/29 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 图——关键路径(代码超详细注释) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

關鍵路徑是圖中一個比較重要的知識點,它的用處也很大,例如可以幫助企業哪些生產步驟是整個生產進度的關鍵,提高這些生產步驟的效率就能提高整個生產過程的效率。

關鍵路徑的關鍵是要了解四個概念,即事件最早發生時間,事件最晚發生時間,活動最早發生時間,活動最晚發生時間。它們的定義如下:

敲黑板~~

事件最早發生時間:即頂點的最早發生時間

事件最晚發生時間:即頂點的最晚發生時間

活動最早發生時間:活動最早開工時間,即弧的最早發生時間

活動最晚發生時間:活動在不推遲工期的前提下的最晚發生時間,即弧的最晚發生時間


理解了這四個概念,接下來就一片明朗了,

首先用拓撲排序記錄下各個事件的發生順序(用棧),并依次計算出事件的最早發生時間。

然后依次出棧,從匯點倒推回各個事件的最晚發生時間。

最后,再計算出活動最早發生時間(活動最早發生時間與弧頭頂點的最早發生時間相同),以及活動最晚發生時間(活動最遲發生時間等于弧尾頂點的最晚發生時間減去邊的權重)。大功告成!

上代碼,超詳細注釋哦~~~~~~~~~~

測試用的圖,圖的儲存結構采用鄰接表式,各個邊表結點還儲存有邊的權重。

/*------------------------------------
*		關鍵路徑的代碼實現
*------------------------------------*/

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


總結

以上是生活随笔為你收集整理的图——关键路径(代码超详细注释)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。