題目:
給定10個結點以及結點間的權值,試着求解其任意兩點間的關鍵路徑。
分析:
AOE網原本是存在入點和出點的,這里求“任意節點”,所以會出現不存在的情況。(雖然我覺得這部分不是很必要…)
基本步驟參考了這篇,寫得非常好,一個例子遠比大段文字描述來得清晰明了。
由於上面那篇文章里的例子是9個點,而題目要求的是10個點,我在v1前面加了一個v0,對結果沒有什么影響。
代碼如下:
/*算法:
1.輸入邊數m;
2.初始化權重d[i][j]為max(0<=i<m,0<=j<m);
3.輸入每條邊的起點u終點v及其權重w,設置d[u][v]=w;
4.輸入要查詢的兩點first和last;
5.初始化的earliest[i]=0; latest[i]=max; path[i]=max(0<=i<10);
6.從k=first開始(earliest[first]=0),遞歸查找下一個節點i,然后計算各個點最早開始的時間earliest[i],如果earliest[k]+d[k][i]>earliest[i]則更新earliest[i];如果發現沒有任何節點i與k相連,則輸出“路徑不存在”;
7. 從k=last開始(latest[last]=earliest[last]),遞歸查找上一個節點i,然后計算各個點最晚開始的時間latest[i],如果latest[k]-d[i][k]<latest[i]則更新latest[i];
8. 從k=first開始,循環查找下一個節點i,如果latest[i]-d[k][i]==earliest[k],則k->i為關鍵路徑,把i加入到path中。
9.打印輸出path的內容
*/
#include<iostream>
using namespace std;
#define max 1000000
int d[10][10];
int earliest[10];
int latest[10];
int path[10];
void findEarliest(int k,int last);
void findLatest(int k,int first);
bool flag=false;//用於判斷是否存在關鍵路徑
int main(){
int i,j,k,m,n=10;
int u,v,w;
int first,last,count=0;
int next;
cout<<"請輸入邊數:";
cin>>m;
for(i=0;i<m;i++){
for(j=0;j<m;j++)
d[i][j]=max;
}
cout<<"請輸入每條邊的頂點及其權重"<<endl;
for(i=0;i<m;i++){
cin>>u>>v>>w;
d[u][v]=w;
}
cout<<"請輸入要查詢的兩點:";
cin>>first>>last;
for(i=0;i<10;i++){
earliest[i]=0;
latest[i]=max;
path[i]=max;
}
k=first;path[0]=k;count=1;
findEarliest(k,last);
if(!flag){
cout<<"路徑不存在";
return 0;
}
k=last;latest[k]=earliest[k];
findLatest(k,first);
k=first;
while(k!=last){
for(i=0;i<10;i++){
if(d[k][i]!=max&&(latest[i]-d[k][i]==earliest[k])){
path[count++]=i;
k=i;
break;
}
}
}
cout<<"關鍵路徑為:"<<endl;
for(i=0;path[i]!=last;i++){
cout<<path[i]<<"->";
}
cout<<path[i];
}
void findEarliest(int k,int last){
if(k==last)
return;
flag=false;
for(int i=0;i<10;i++){
if(d[k][i]<max){
flag=true;
if((earliest[k]+d[k][i])>earliest[i])
earliest[i]=earliest[k]+d[k][i];
findEarliest(i,last);
}
}
//如果flag沒有在循環中被修改為ture,則說明沒有節點與k相連(即沒有進入if語句內,函數返回不再進行遞歸),然后在主函數中判斷flag的值來決定是否繼續
}
void findLatest(int k,int first){
if(k==first)
return;
for(int i=0;i<10;i++){
if(d[i][k]<max){
if(latest[k]-d[i][k]<latest[i])
latest[i]=latest[k]-d[i][k];
findLatest(i,first);
}
}
}
結果截圖:
反思:
采用遞歸和大量循環遍歷在時間上效率很低。本題只有十個點,如果數據規模較大,改成用指針查找或許比較快,但是數據結構的建立就比較麻煩了。