Leetcode 2050 Parallel Courses III

今天刷到了这样一道题, 同时涉及了拓扑排序和动态规划算法,记录一下解题思路
题目如下

You are given an integer n, which indicates that there are n courses labeled from 1 to n. You are also given a 2D integer array relations where relations[j] = [prevCoursej, nextCoursej] denotes that course prevCoursej has to be completed before course nextCoursej (prerequisite relationship). Furthermore, you are given a 0-indexed integer array time where time[i] denotes how many months it takes to complete the (i+1)th course.

You must find the minimum number of months needed to complete all the courses following these rules:

You may start taking a course at any time if the prerequisites are met.
Any number of courses can be taken at the same time.
Return the minimum number of months needed to complete all the courses.

Note: The test cases are generated such that it is possible to complete every course (i.e., the graph is a directed acyclic graph).

首先由于课程有互相依赖, 我们需要决定上课顺序, 这部分使用拓扑排序来解决
其主要思路是构建入度表, 寻找当前入度为0的课程,也就是前置课程已经上完的课
在完成每一门课程后, 检查它的后置课程的入度,如果也是0就加入课程列表

本题允许同时上无限门课故
状态转移方程: 完成dp[i]课程后的时间 = dp[i]课程话费的时间 + max(dp[i]的前置课程最迟的一门的完成时间)

代码如下

import collections


class Solution:
    def minimumTime(self, n: int, relations: List[List[int]], time: List[int]) -> int:
        # 入读表
        indegree = [0] * n
        # 邻接表
        adjacency = collections.defaultdict(list)
        # 逆邻接表
        reversedAdjacency = collections.defaultdict(list)
        # 完成dp[i]课程后的时间
        # 状态转移方程: 完成dp[i]课程后的时间 = dp[i]课程话费的时间 + max(dp[i]的前置课程最迟的一门的完成时间)
        dp = [0] * n
        # 初始化入读表、邻接表、逆邻接表(坐标改为0开始的)
        for outNode, inNode in relations:
            indegree[inNode-1] += 1
            adjacency[outNode-1].append(inNode-1)
            reversedAdjacency[inNode-1].append(outNode-1)
        queue = collections.deque()

        # 寻找没有前置课程的课程作为第一批学习的课程
        for i in range(n):
            if indegree[i] == 0:
                queue.append(i)
                # 对于入度为0的点,即无前置课程的课程,完成的时间即课程所花费的时间
                dp[i] = time[i]

        while queue:
            # 学习队列中的课程
            course = queue.popleft()
            # 寻找前置课程中最后完成的一个
            pre_course_max = 0
            for pre_course in reversedAdjacency[course]:
                    pre_course_max = max(pre_course_max, dp[pre_course])
            # 根据状态转移方程更新这门课程的完成时间
            dp[course] = pre_course_max + time[course]
            # 找出已完成前置课程的课, 加入待学习课程队列
            for c in adjacency[course]:
                indegree[c] -= 1
                if indegree[c] == 0:
                    queue.append(c)
        return max(dp)

你可能感兴趣的:(Leetcode 2050 Parallel Courses III)