7-11 關鍵活動 (30 分)

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章