数据结构 08-图8 How Long Does It Take (25 分)

Given the relations of all the activities of a project, you are supposed to find the earliest completion time of the project.

Input Specification:

Each input file contains one test case. Each case starts with a line containing two positive integers N (100), the number of activity check points (hence it is assumed that the check points are numbered from 0 to N1), and M, the number of activities. Then M lines follow, each gives the description of an activity. For the i-th activity, three non-negative numbers are given: S[i]E[i], and L[i], where S[i] is the index of the starting check point, E[i] of the ending check point, and L[i] the lasting time of the activity. The numbers in a line are separated by a space.

Output Specification:

For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output "Impossible".

Sample Input 1:

9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
 

Sample Output 1:

18
 

Sample Input 2:

4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5
 

Sample Output 2:

Impossible

 

 

核心思路 用拓扑算法检测图中是否有环存在,如果存在环则输出"Impossible" , 如果是有向无环图DAG(Directed Acyclic Graph) 则输出关键路径的总权值 

在进行拓扑排序输出的时候, 可以一同完成 活动时间的计算 和 关键路径的标记

 

拓扑算法核心

bool toplogicalSort(){
        //toplogicSort检查DAG有向无环图(Directed Acyclic Graph)是否存在环
        int count{0};//记录拓扑排序序列中的结点数量
        vector<int> queue(0);
        int temp;
        vector<int> visited(size);
        for(int i=0;i<size;i++){//入度为0的结点入栈
            if(!events[i]->indegree){
                queue.push_back(i);
                count++;
                visited[i]=1;
            }
        }
        while(!queue.empty()){//栈不为空时说明有入度为0的结点存在
            temp=queue.front();
            queue.erase(queue.begin());
            for(int i=0;i<size;i++){
                if(!visited[i]&&vertexs[temp][i]<9999){//将所有入度为temp的结点 入度-1
                    if(!(--events[i]->indegree)){//如果入度为0则加入队列
                        visited[i]=1;
                        queue.push_back(i);
                        count++;
                    }
                }
            }
        }
        //如果count不等于events.size()说明存在环
    }

 

在拓扑排序过程中, 如果一个结点 j 入度为0 需要入队进行迭代

  与此同时 结点 i 的前继任务全部完成, 此时对结点 i 的前继任务进行遍历可以算出到结点 j 的关键路径和关键路径长度,

      寻找( i 的前继结点 j 最早开始时间 + 前继结点 j 到结点 i ) 的最大值  (es是early start的缩写)  , 这个所需时间最大值的 前继结点 同时也是结点i的关键路径结点

      vertexs[j][i]中存的是有向图 由 j 到 i 的长度

for(int j=0;j<size;j++){//找出这个入度为0的结点中 前继结点到这个点的最大时间
    if(vertexs[j][i]<9999 &&  visited[j] && events[j]->es + vertexs[j][i]> events[i]->es){
        events[i]->es = events[j]->es + vertexs[j][i];
        events[i]->keyEvent=j;//哪个结点到这个结点耗时最多 这个结点就是当前结点的关键路径
    }
}

 

    

 

 

#include <iostream>
#include <vector>
using namespace std;
//计算关键路径长度
class event{
public:
    int es{0};//最早发生时间
    int ef{0};//最晚发生时间
    int ls{9999};//最晚开始时间
    int lf{9999};//最晚结束时间
    int indegree{0};//入度
    int outgegree{0};//出度
    int keyEvent{-1};
};
class matricGraphic{
public:
    vector<event*> events;
    vector<vector<int>> vertexs;
    matricGraphic()=default;
    int size;
    void build(int n,int m){
        int a,b;
        size=n;
        for(int i=0;i<n;i++){
            event* newevent=new event;
            events.push_back(newevent);
        }
        vertexs=vector<vector<int>>(n,vector<int>(n,9999));//初始值为9999
        for(int i=0;i<m;i++){
            scanf("%d %d",&a,&b);
            scanf("%d",&vertexs[a][b]);
            events[a]->outgegree++;//a的出度++
            events[b]->indegree++;//b的入度++
        }
    }
    bool toplogicalSort(){
        //toplogicSort检查DAG有向无环图(Directed Acyclic Graph)是否存在环
        //栈中存的是入度为0的点 但是本题中默认只有起点0是入度为0
        int count{0};//记录拓扑排序序列中的结点数量
        vector<int> stack(0);
        int temp;
        vector<int> visited(size);
        for(int i=0;i<size;i++){//入度为0的结点入栈
            if(!events[i]->indegree){
                stack.push_back(i);
                count++;
                visited[i]=1;
            }
        }
        while(!stack.empty()){//栈不为空
            temp=stack.front();
            stack.erase(stack.begin());
            for(int i=0;i<size;i++){
                if(!visited[i]&&vertexs[temp][i]<9999){//将所有入度为temp的结点 入度-1
                    if(!(--events[i]->indegree)){//如果入度为0则加入队列
                        visited[i]=1;
                        stack.push_back(i);
                        count++;
                        for(int j=0;j<size;j++){//找出这个入度为0的结点中 前继结点到这个点的最大时间
                            if(vertexs[j][i]<9999 &&  visited[j] && events[j]->es + vertexs[j][i]> events[i]->es){
                                events[i]->es = events[j]->es + vertexs[j][i];
                                events[i]->keyEvent=j;//哪个结点到这个结点耗时最多 这个结点就是当前结点的关键路径
                            }
                        }
                    }
                }
            }
        }
        //如果count不等于events.size()说明存在环
        if(count==size){
            int max{0};
            for(int i=0;i<size;i++){
                if(events[i]->es>max){
                    max=events[i]->es;
                }
            }
            cout << max <<endl;
            return  true;
        }else{
            cout << "Impossible"<<endl;
            return false;
        }
    }
};
int main(){
    int n,m;
    cin >> n >> m;
    matricGraphic MG;
    MG.build(n, m);
    if(m>=n-1){
        //如果是DAG有向无环图
        MG.toplogicalSort();
    }else{
        cout << "Impossible"<<endl;
    }
    return 0;
}

 

posted @ 2021-05-25 01:09  keiiha  阅读(104)  评论(0编辑  收藏  举报