PTA-How long does it take?

本文介绍了一种使用拓扑排序算法解决有向图中关键路径寻找问题的方法。通过计算每个节点的入度和最早完成时间,算法能够确定任务之间的依赖关系,并找出完成所有任务所需的最长路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <queue>
#include <memory.h>

#define MAX 101
using namespace std;

int n, m;
int edge[MAX][MAX];        //紀錄活動耗費時間 
int dp[MAX];    //紀錄最早完成任務i的時間 
int rd[MAX];    //紀錄i的入度
int vis[MAX];    //判斷是否已經加入隊列 

void jiSuanRD();
void topSort();
void init();
int main(){
    int v1, v2, weight;
    init();
    //建圖 
    scanf("%d %d", &n, &m);
    for(int i = 0; i< m; i++){
        scanf("%d %d %d", &v1, &v2, &weight);
        edge[v1][v2] = weight;        //有向圖 
    }    
    topSort();
    return 0;
}

void init(){
    memset(rd, 0, sizeof(rd));
    memset(vis, 0, sizeof(vis));
    memset(edge, 0, sizeof(edge));
    memset(dp, 0, sizeof(dp));

void topSort(){
    jiSuanRD();        //計算各頂點的入度 
    dp[0] = 0;        //初始值 
    queue<int> q;
    int flag = 1;    //判斷是否有任务点加入 
    int cnt = 0;    //已完成的任務數目 
    while(flag){
        flag = 0;
        for(int i = 0; i < n;  i++){
            if(vis[i] == 0 && rd[i] == 0){
                q.push(i);
                vis[i] = 1;            //需要遍歷完所有結點,不加vis的話最出現死循環,因為rd[i]最后都都等於0 
                flag = 1;        //循環結束的判定條件 
                cnt ++;            //決定能否完成所有任務 
            }
        }
        while(!q.empty()){
            int tmp = q.front();
            q.pop();
            for(int i = 0; i < n; i ++){
                if(edge[tmp][i]){        //tmp->i,求出任務i最早完成時間 
                    if(dp[i] < edge[tmp][i] + dp[tmp]){
                        dp[i] = edge[tmp][i] + dp[tmp];
                    }
                    rd[i] --;    //結點i的入度減1 
                }    
            }
        }
    }
    if(cnt == n){
        int max = 0;
        for(int i = 0; i< n;  i++){        //n-1不一定就是終點 
            if(dp[i] > max){
                max = dp[i];
            }
        } 
        printf("%d\n", max);
    }
    else {        //證明有環路存在 
        printf("Impossible\n");
    } 
}

void jiSuanRD(){
    for(int i =0; i< n;  i++){
        for(int j = 0; j < n; j ++){
            if(edge[i][j]){
                rd[j] ++;
            }    
        } 
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值