7-2 关键路径

假定一个工程由若干子任务构成,使用一个包含n个顶点、e条边的AOE网表示该工程,顶点编号为1至n,有向边表示该工程的每个子任务,边的权值表示完成该子任务所需的时间,假定网中只含一个源点和一个汇点。请编写程序求出该工程的所有关键活动,并计算完成该工程所需的最短时间。

输入格式:

每个测试点包含多组测试数据。每组数据第一行为2个整数n和e,均不超过200,分别表示AOE网的顶点数和边数。接下来e行表示每条边的信息,每行为3个正整数a、b、c,其中a和b表示该边的端点编号,c表示权值。各边并不一定按端点编号顺序排列,且各顶点并不一定按拓扑序排列。

输出格式:

对每组数据,若工程不可行(AOE网中存在环),输出“unworkable project”;若工程可行,则输出第一行为完成工程所需的最短时间,并从第2行开始输出关键活动,每个关键活动占一行,格式为i->j,其中i和j表示关键活动所在边的端点编号。各关键活动输出顺序为:按i的递增顺序输出,若多个关键活动的i值相同,则按j的递增顺序输出。

输入样例:

4 4
1 2 6
1 3 4
2 4 1
3 4 1

 

输出样例:

7
1->2
2->4
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010;
int a[N][N],n;
int in[N],dis[N];
int out[N],rdis[N];
int vec[N],cnt;
int main(){
    int m;
    while(cin>>n>>m){//读取n和m的值
        cnt=0;
        for(int i=0;i<=n;i++){
            for(int j=1;j<=n;j++){
                a[i][j]=0;
            }
        }
        //memset(a,0,sizeof(a));//清空邻接矩阵
        memset(in,0,sizeof in);//初始化in数组
        memset(out,0,sizeof out);//初始化out数组
        memset(dis,0,sizeof dis);//初始化dis数组
        memset(rdis,0x3f,sizeof(rdis));//初始化rdis数组为无穷大

        for(int i=0;i<m;i++){
            int u,v,d;
            cin>>u>>v>>d;//读取边的起点、终点、和权重
            in[v]++;//终点入度增加
            out[u]++;//起点出度增加
            a[u][v]=d;//邻接矩阵中记录边的权重
        }
        int o=-1;
        bool ji=false;
        for (int i=1;i<=n;i++){
            if(in[i]==0){//找到唯一的入度为0的点
                if(o==-1){//找到第一次到入度为0的点
                    o=i;
                }else{//找到多个入度为零的点,无法确定起点
                    ji=true;
                    break;
                }
            }
        }
        if(o==-1||ji){//无法确定起点,输出“unworkable project”
            cout<<"unworkable project"<<endl;
            continue;
        }
        vec[cnt++]=o;//将起点o加入存储路径的数组vec[]

        while(cnt>0){
            int p=vec[--cnt];//取出路径数组中的最后一个点
            for(int i=1;i<=n;i++){
            if(a[p][i]>0){
                in[i]--;//删除点p到点i的边,终点i的入度减一
                if(dis[i]<dis[p]+a[p][i]){
                    dis[i]=dis[p]+a[p][i];//更新点i的最长路径值
                }
                if(in[i]==0){
                    vec[cnt++]=i;//终点i入度为0,加入路径数组vec[]
                }
                }
            }
        }
        bool fl=true;
        for(int i=1;i<=n;i++){
            if(in[i]>0){//存在入读不为0的点,说明有环,输出“uunworkable project”
                fl=false;
                break;
            }
        }
        if(!fl){
            cout<<"unworkable project"<<endl;
            continue;
        }
        int tmp=vec[0];
        rdis[vec[0]]=dis[vec[0]];//将起点的最长路径赋值给rdis[tmp]
        cnt++;
        while(cnt>0){
            int p=vec[--cnt];//取出路径数组中的最后一个点
            for(int i=1;i<=n;i++){
                if(a[i][p]>0){
                    out[i]--;//删除点i到点p的边,起点i的出度减一
                    if(rdis[i]>rdis[p]-a[i][p]){
                        rdis[i]=rdis[p]-a[i][p];//更新点i的最长路径值
                    }
                    if(out[i]==0){
                        vec[cnt++]=i;//起点i出度为0,加入路径数组vec[]
                        
                    }
                }
            }
        }
        cout<<dis[tmp]<<endl;//输出最长路径值
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(a[i][j]>0&&dis[i]==rdis[i]&&dis[j]==rdis[j]&&dis[i]+a[i][j]==dis[j]){
                    cout<<i<<"->"<<j<<endl;//输出满足条件的边
                }
            }
        }
        break;//结束程序
    }
    return 0;
}

 



posted @ 2023-06-26 21:50  一个小虎牙  阅读(207)  评论(0编辑  收藏  举报