2021.10.28 力扣-并行课程 III-拓扑排序算法练习

题目描述:

给你一个整数 n ,表示有 n 节课,课程编号从 1 到 n 。同时给你一个二维整数数组 relations ,其中 relations[j] = [prevCoursej, nextCoursej] ,表示课程 prevCoursej 必须在课程 nextCoursej 之前 完成(先修课的关系)。同时给你一个下标从 0 开始的整数数组 time ,其中 time[i] 表示完成第 (i+1) 门课程需要花费的 月份 数。

请你根据以下规则算出完成所有课程所需要的 最少 月份数:

如果一门课的所有先修课都已经完成,你可以在 任意 时间开始这门课程。
你可以 同时 上 任意门课程 。
请你返回完成所有课程所需要的 最少 月份数。

注意:测试数据保证一定可以完成所有课程(也就是先修课的关系构成一个有向无环图)。

方法一:

class Solution{
public:
    struct course
    {
        list<int> adj;
        int starttime;      //开始时间,等于其所有先修课中的最晚结束时间
        int endtime;        //结束时间
        int spendtime;      //该课程需花费的时间
    };
    int minimumTime(int n, vector<vector<int>>&relations, vector<int>&time) {
        int m = relations.size();           //m等于边数
        vector<course> cous(n + 1);
        vector<int> innum(n + 1);           //存储各个点的入度
        queue<int> que;                     //用队列存储入度为0的点
        //存图
        for (int i = 0; i < m; i++)
        {
            //一条a -> b的边
            int a = relations[i][0];
            int b = relations[i][1];
            cous[a].adj.push_back(b);
            innum[b]++;
        }
        //初始化每个点的开始、结束、花费时间
        for (int i = 0; i < n; i++)
        {
            cous[i + 1].starttime = 0;
            cous[i + 1].endtime = time[i];
            cous[i + 1].spendtime = time[i];
        }

        for (int i = 1; i <= n; i++)
        {
            if (innum[i] == 0)
            {
                que.push(i);
            }
        }
        while (!que.empty())
        {
            //找出一个入度为0的点a,将点a和与a相连的边都删去
            int a = que.front();
            que.pop();
            list<int>::iterator iter;
            for (iter = cous[a].adj.begin(); iter != cous[a].adj.end(); iter++)
            {
                int b = *iter;
                //课程a是课程b的先修课,如果课程a的结束时间大于课程b的开始时间,就更新课程b的开始时间和结束时间
                if (cous[a].endtime > cous[b].starttime)
                {
                    cous[b].starttime = cous[a].endtime;
                    cous[b].endtime = cous[b].starttime + cous[b].spendtime;
                }
                //删去边之后,节点b的入度减一,若为0则入队
                innum[b]--;
                if (innum[b] == 0)
                {
                    que.push(b);
                }
            }
        }
        //完成所有课程的最少时间,就是课程中最晚结束的课程的结束时间
        int ans = INT_MIN;
        for (int i = 1; i <= n; i++)
        {
            ans = max(ans, cous[i].endtime);
        }
        return ans;
    }
};

很容易想到要用拓扑排序来解决,有关拓扑排序的内容参考:

拓扑排序入门(真的很简单)_安得广厦千万间的博客-CSDN博客_拓扑排序

在拓扑排序的基础上,只需要加入每一门课程的开始时间、结束时间和花费时间即可,在使用拓扑排序的过程中顺便更新,最后需要的完成所有课程的最少时间,就是所有课程中最晚结束的那门课程的最晚结束时间(有关最早开始时间、最晚结束时间的概念,我记得是曾在数据结构一门课中学过的有关aoe图和关键路径的知识)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值