图——关键路径(代码超详细注释)
生活随笔
收集整理的這篇文章主要介紹了
图——关键路径(代码超详细注释)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
關鍵路徑是圖中一個比較重要的知識點,它的用處也很大,例如可以幫助企業哪些生產步驟是整個生產進度的關鍵,提高這些生產步驟的效率就能提高整個生產過程的效率。
關鍵路徑的關鍵是要了解四個概念,即事件最早發生時間,事件最晚發生時間,活動最早發生時間,活動最晚發生時間。它們的定義如下:
敲黑板~~
事件最早發生時間:即頂點的最早發生時間
事件最晚發生時間:即頂點的最晚發生時間
活動最早發生時間:活動最早開工時間,即弧的最早發生時間
活動最晚發生時間:活動在不推遲工期的前提下的最晚發生時間,即弧的最晚發生時間
理解了這四個概念,接下來就一片明朗了,
首先用拓撲排序記錄下各個事件的發生順序(用棧),并依次計算出事件的最早發生時間。
然后依次出棧,從匯點倒推回各個事件的最晚發生時間。
最后,再計算出活動最早發生時間(活動最早發生時間與弧頭頂點的最早發生時間相同),以及活動最晚發生時間(活動最遲發生時間等于弧尾頂點的最晚發生時間減去邊的權重)。大功告成!
上代碼,超詳細注釋哦~~~~~~~~~~
測試用的圖,圖的儲存結構采用鄰接表式,各個邊表結點還儲存有邊的權重。
/*------------------------------------
* 關鍵路徑的代碼實現
*------------------------------------*/
#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;
}
總結
以上是生活随笔為你收集整理的图——关键路径(代码超详细注释)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: opencv实现人脸识别(五) 运用tk
- 下一篇: 插件库网站