7-11 關鍵活動 (30 分)
關鍵路徑問題。
一開始我把問題想簡單了,以爲只要拓撲排序,然後再求最早的完成時間。再求最早時間的時候記錄路徑就行了。但是發現和我想的不大一樣。
經過我再一次的思考發現,要把最早時間,最晚時間,邊的機動時間。都求出來了纔可以,唉,這不就是典型的關鍵路徑嗎。
大體思路如下:
1、讀入數據,得到每個結點的入度出度。
2、用拓撲排序得到任務完成的先後順序。
3、根據拓撲排序的結果,求出任務最早的完成時間。
4、根據最早時間和是不是有出度,求出最晚完成時間。
5、根據最早完成時間和最晚時間,求出邊的機動時間。
6、根據機動時間得到結果。
代碼:
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int MAX = 110;
struct Edge{
int s,e,cost,index,motive;
Edge() {}
Edge(int x,int y,int z,int m=0,int n=0):s(x),e(y),cost(z),index(m),motive(n) {}
};
int N,M,indegree[MAX],sorted[MAX],earliest[MAX],lastliest[MAX],outdegree[MAX];
vector<Edge> E;
vector<Edge> KeyPath;
bool compare(Edge a,Edge b){
if(a.s != b.s){
return a.s < b.s; //升序
} else {
return a.index > b.index; //降序
}
}
bool TopSorted(){ //拓撲排序
int count = 0;
queue<int> q;
for(int i=1;i<=N;i++){//頂點從一編號
if(indegree[i] == 0){
q.push(i);
sorted[count++] = i;
}
}
while(!q.empty()){
int temp = q.front();
q.pop();
for(int i=0;i<M;i++){
if(indegree[E[i].e] != 0 && E[i].s == temp){
indegree[E[i].e]--;
if(indegree[E[i].e] == 0){
q.push(E[i].e);
sorted[count++] = E[i].e;
}
}
}
}
if(count == N) return true;
else return false;
}
int main(){
int v1,v2,c,weight = 0;
bool result;
scanf("%d%d",&N,&M);
for(int i=0;i<M;i++){
scanf("%d%d%d",&v1,&v2,&c);
E.push_back(Edge(v1,v2,c,i));
indegree[v2]++; //入度
outdegree[v1]++; //出度
}
result = TopSorted();
if(!result){
printf("0\n");
} else {
for(int i=0;i<N;i++){ //計算earliest[],用sorted[i]裏的數據
int Max = 0;
for(int j=0;j<M;j++){
if(E[j].e == sorted[i] && E[j].cost+earliest[E[j].s] > Max){
Max = E[j].cost + earliest[E[j].s];
}
}
earliest[sorted[i]] = Max;
}
for(int i=1;i<=N;i++){ //對每個出度爲零的點,lastliest[]賦值
if(outdegree[i] == 0){
lastliest[i] = earliest[i];
}
}
for(int i=N-2;i>=0;i--){ //計算lastliest[]
int Min = 65535;
for(int j=0;j<M;j++){
if(E[j].s == sorted[i] && lastliest[E[j].e] - E[j].cost < Min){
Min = lastliest[E[j].e] - E[j].cost;
}
}
lastliest[sorted[i]] = Min;
}
for(int i=0;i<M;i++) //計算邊的機動時間
E[i].motive = lastliest[E[i].e] - E[i].cost - earliest[E[i].s];
for(int i=1;i<=N;i++) //輸出結果
if(earliest[i] > weight)
weight = earliest[i];
printf("%d\n",weight);
for(int i=0;i<M;i++){
if(E[i].motive == 0){
KeyPath.push_back(E[i]);
}
}
sort(KeyPath.begin(),KeyPath.end(),compare); //對輸出結果排序
for(auto it = KeyPath.begin();it != KeyPath.end();it++) //迭代器訪問
printf("%d->%d\n",it->s,it->e);
}
system("pause");
return 0;
}