儘管是用c++編譯的,但程式中沒有應用什麼c++特性,應該算是c語言編寫吧。
一、概述
工程上常常用乙個有向無環圖來代表乙個專案(如下圖)。
以節點表示某個事件,以邊表示活動,邊上的數字表示活動的持續時間。在工程分析上,常常需要找到一條「關鍵路徑」,即此路徑直接決定專案的持續時間。
二、演算法描述
為求出關鍵路徑,首先要明確以下幾個概念:
c1.節點的最早可能開始時間ev
c2.節點的最遲允許開始時間lv
c3.活動(即邊)的最早可能開始時間ee
c4.活動的最遲允許開始時間le
c1: ev比較容易理解,設起點的最早開始時間為0,下乙個節點的ev就是上乙個節點的ev加上邊的持續時間;若存在多條路徑到達同一節點的情況,則取最大值為該點的ev(因為只有前面所有活動全部完成後該點才能啟動)
c2: lv則要採用倒推的方式,如果已知終點的ev為t,則與終點直接相連節點的lv=t-邊的持續時間;如果存在多條路徑,ev取最小值。
c3: 邊的ee等於其起點的ev
c4:邊的le等於其終點的lv減去邊的持續時間
演算法書上指出:對於圖中某條邊,如果滿足 ev=lv,則此邊為關鍵路徑(的組成部分)
三、演算法實現
3.1輸入描述
第一行輸入圖的頂點個數n 和邊數m,
第二行開始是邊的資訊,每條邊的資料佔一行,格式為:s e t(即表示從頂點s 到頂點e 的一條權值為t的邊)頂點編號從0開始!(為了程式設計方便)
對於上面的圖,可以寫為:
9 11
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
3.2 輸出描述
the critical path:
a1:0->1
a4:1->4
a8:4->7
a7:4->6
a10:6->8
a11:7->8
其中,an中n表示邊的編號,對應於輸入的順序
3.3 程式實現
/*
資料輸入時採用如下的格式:
首先輸入頂點個數n 和邊數m,
然後輸入每條邊,每條邊的資料佔一行,格式為:s e t;表示從頂點s 到頂點e 的一條權值為t的邊
頂點編號從0開始!(為了程式設計方便)
2016.7.22 by pospro
詳見:*/#include #include #define maxn 100 //the max num of vertex
#define maxm 200 //the max num of edges
using namespace std;
struct arcnode //儲存邊的資訊
;//全域性變數!
int n,m; //the number of vertex and edge,
arcnode* outedge[maxn]; //記錄每個頂點對應的出邊表
arcnode* inedge[maxn]; //記錄每個頂點對應的入邊表
int outord[maxn]; //每個頂點的出度
int inord[maxn]; //每個頂點的入度
int ev[maxn]; //earliest start time for vertex
int lv[maxn]; //latest start time for vertex
int ee[maxm]; //maxm!! earliest start time for edge
int le[maxm]; //latest start time for edge!!
void criticalpath()
//其它的都是套路(實現拓撲排序的套路),下面這兩句才是為求關鍵路徑而生的
//如果到達該點有多個路徑,最早開始時間必然是個值中的最大值!(因為有一條路徑未完成,該點就不能啟動)
//第乙個起點的ev值,在初始化時就被設為0了
if(ev[nxt]dur+ev[tmp])
ev[nxt]=tpnode->dur+ev[tmp];
tpnode=tpnode->next;}}
}//以入度鄰接表,再來一遍
int maxtime=0;
for(i=0;imaxtime)
maxtime=ev[i];
top=-1; //重新設棧頂
for(i=0; ito; //其實是找上乙個點
outord[nxt]--;
if(0==outord[nxt])
//下面兩句計算最遲開始時間
//只要有一條路徑決定它在更早的時間開始,就得更早開始,所以取各路徑最小值
if(lv[nxt]>(lv[tmp]-tpnode->dur))
lv[nxt]=(lv[tmp]-tpnode->dur);
tpnode=tpnode->next;}}
}//上面計算的都是節點(!)的最早和最遲開始時間,下面需要計算邊的
//若邊(活動)的最早開始==最遲開始時間,則該邊為關鍵路徑
printf("the critical path:\n");
for(i=0; ino; //tmp此時儲存邊的編號!!
nxt=tpnode->to;
ee[tmp]=ev[i];//邊的最早開始時間就是其起點的最早開始時間
le[tmp]=lv[nxt]-tpnode->dur; //邊的最遲開始時間,是其終點的最遲開始時間減去邊的持續時間
if(ee[tmp]==le[tmp])
printf("a%d:%d->%d\n",tmp,i,nxt);
tpnode=tpnode->next;}}
}int main()
//構建入邊表
inord[e]++;
newnode=new arcnode; // 必須重新賦值
newnode->to=s;
newnode->no=i+1;
newnode->dur=t;
newnode->next=null;
if(inedge[e]==null)
inedge[e]=newnode;
else
}//一次性獲得全部輸入後,執行程式的核心部分——找出關鍵路徑
criticalpath();
//release the memory
for(i=0;inext; //newnode不是新節點,只是借用一下其名字
delete outedge[i];
outedge[i]=newnode;
}while(inedge[i]!=null)
}return 0;
}
關鍵路徑 C語言實現
include include define maxvertexnum 50 define false 0 define true 1 typedef int bool typedef int vertex typedef int weighttype struct vertexnode 頂點結構 ...
關鍵路徑 C語言簡單實現
本文參考自 大話資料結構 對關鍵路徑的理解參考自 在乙個表示工程的帶權有向圖中,用頂點表示事件,用有向邊表示活動,用邊上的權值表示活動的持續時間,這種有向圖的邊表示活動的網,我們稱之為aoe網。我們把aoe網中沒有入邊的頂點稱為始點或源點,沒有出邊的頂點稱為終點或匯點。儘管aoe網和aov網都是用來...
用遺傳演算法求解迷宮路徑問題(c語言實現)
include include include include include include include include using namespace std define maph 100 高 define mapw 100 寬 define playersnumber 10000 每代個...