在介紹關鍵路徑之前,先介紹一個拓撲排序。其實這個概念我並不是很理解,通俗的講就是由一個節點出發,會一直走到後面的節點,不會返回到已經訪問過的節點,如何判斷一個圖是否是拓撲排序。(1)在有向圖中選一個沒有前驅的頂點輸出,(2)刪除該頂點和所有以它為尾的弧。直至圖中沒有節點或沒有入度為0的點。
在此基礎上,引入關鍵路徑,在拓撲排序的基礎上加上邊的權值,完成一個工程從開始點到完成點的最長路徑的長度。路徑長度最長的路徑叫做關鍵路徑,關鍵路徑上的所有活動都是關鍵活動。關鍵活動就是要找e(i)==l(i),時間最早發生時間ve,時間最晚發生時間vl。這個概念我也很難解釋,挺難說清楚的,自己多看看例子吧。如何求解ve和vl呢。ve(0)=0開始向前遞推ve(j) = max{ve(i)+dut(i,j)};求出ve後,vl(n-1) =
ve(n-1);向後遞推,vl(i) = Min{vl(j) - dut(i,j)};
#include "graph.h"
#include <stdio.h>
#include <queue>
#include <stack>
using namespace std;
//#define DEBUG
stack<int> s; //儲存拓撲逆序
int ve[MAX_VERTEX_NUM]; //記錄最早時間
int vl[MAX_VERTEX_NUM]; //記錄最晚時間
/*********************************************/
/* 拓撲排序 */
/* 參數:G */
/* 功能 檢查圖中是否有環 */
/*********************************************/
void TopologicalSort(const MGraph *g)
{
int indegree[MAX_VERTEX_NUM]; //入度
int i,j;
for(i=0;i<g->vexnum;i++)
{
indegree[i] = 0;
ve[i] = 0;
}
//初始化節點的入度
for(i=0;i<g->vexnum;i++)
for(j=0;j<g->vexnum;j++)
{
if(g->arcs[i][j]!=INT_MAX)
{
indegree[j]++;
}
}
int count=0; //輸出節點的個數
queue<int> q; //存放入度為0的點
for(i=0;i<g->vexnum;i++)
{
if(!indegree[i])
{
q.push(i);
indegree[i]--; //表明已入過隊列
}
}
//依次輸出入度為0的點
//沒輸出一個點將相連點的入度減1
//再將入度為0的點入隊列
while(!q.empty())
{
int temp;
temp = q.front();
s.push(temp); //依次逆序進棧
// printf("%d",g->vexs[i]);
count++;
for(i=0;i<g->vexnum;i++)
{
if(g->arcs[temp][i]!=INT_MAX)
{
indegree[i]--; //刪除節點,相鄰節點入度減1
if((ve[temp]+g->arcs[temp][i])>ve[i])
{
ve[i] = ve[temp]+g->arcs[temp][i]; //修改最早時間
}
}
}
q.pop();
for(i=0;i<g->vexnum;i++)
{
if(!indegree[i])
{
q.push(i);
indegree[i]--;
}
}
}
if(count != g->vexnum)
printf("There is a ring!\n");
else
{
// printf("拓撲排序完成!\n");
#ifdef DEBUG
for(i=0;i<g->vexnum;i++)
printf("%d ",ve[i]);
printf("\n");
#endif
}
}
//在求最遲發生時間時,我直接拷貝求最早發生時間的做法
//由出度開始升入
void CriticalPath(const MGraph *g)
{
// int outdegree[MAX_VERTEX_NUM]; //出度
int i,j;
for(i=0;i<g->vexnum;i++)
{
// outdegree[i] = 0;
vl[i] = INT_MAX; //在這賦最大值,求的是最小值
}
/* for(i=0;i<g->vexnum;i++)
for(j=0;j<g->vexnum;j++)
{
if(g->arcs[i][j].adj!=INT_MAX)
{
outdegree[i]++;
}
}
*/
int count; //輸出節點的個數
count = s.top();
vl[count] = ve[count];
count = 0;
// queue<int> q; //存放入度為0的點
/* for(i=0;i<g->vexnum;i++)
{
if(!outdegree[i])
{
q.push(i);
vl[i] = ve[i]; //匯點賦值
}
}
*/ //依次輸出入度為0的點
//沒輸出一個點將相連點的入度減1
//再將入度為0的點入隊列
while(!s.empty())
{
int temp;
temp = s.top();
// printf("%d",g->vexs[i]);
count++;
for(i=0;i<g->vexnum;i++)
{
if(g->arcs[i][temp]!=INT_MAX) //以將刪節點為尾的弧
if((vl[temp] - g->arcs[i][temp]) < vl[i])
{
vl[i] = vl[temp]-g->arcs[i][temp];
}
}
s.pop();
/* for(i=0;i<g->vexnum;i++)
{
if(!indegree[i])
q.push(i);
}
*/ }
//求得最遲時間後,可以與最早時間比較。得關鍵路徑。。
if(count != g->vexnum)
printf("There is a ring!\n");
else
{
printf("關鍵路徑:");
#ifdef DEBUG
for(i=0;i<g->vexnum;i++)
printf("%d ",vl[i]);
#endif
}
for(i=0;i<g->vexnum;i++)
if(vl[i] == ve[i])
printf("%d ",g->vexs[i]);
}
/*test
9 11
1 2 3 4 5 6 7 8 9END
1 2 6
1 3 4
1 4 5
2 5 1
3 5 1
4 6 2
5 7 9
5 8 7
6 8 4
7 9 2
8 9 4
end*/