加载中...
LCP 10-二叉树任务调度
发表于:2021-12-03 | 分类: 困难
字数统计: 1.2k | 阅读时长: 4分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/er-cha-shu-ren-wu-diao-du

英文原文

中文题目

任务调度优化是计算机性能优化的关键任务之一。在任务众多时,不同的调度策略可能会得到不同的总体执行时间,因此寻求一个最优的调度方案是非常有必要的。

通常任务之间是存在依赖关系的,即对于某个任务,你需要先完成他的前导任务(如果非空),才能开始执行该任务。我们保证任务的依赖关系是一棵二叉树,其中 root 为根任务,root.leftroot.right 为他的两个前导任务(可能为空),root.val 为其自身的执行时间。

在一个 CPU 核执行某个任务时,我们可以在任何时刻暂停当前任务的执行,并保留当前执行进度。在下次继续执行该任务时,会从之前停留的进度开始继续执行。暂停的时间可以不是整数。

现在,系统有两个 CPU 核,即我们可以同时执行两个任务,但是同一个任务不能同时在两个核上执行。给定这颗任务树,请求出所有任务执行完毕的最小时间。

示例 1:

image.png

输入:root = [47, 74, 31]

输出:121

解释:根节点的左右节点可以并行执行31分钟,剩下的43+47分钟只能串行执行,因此总体执行时间是121分钟。

示例 2:

image.png

输入:root = [15, 21, null, 24, null, 27, 26]

输出:87

示例 3:

image.png

输入:root = [1,3,2,null,null,4,4]

输出:7.5

限制:

  • 1 <= 节点数量 <= 1000
  • 1 <= 单节点执行时间 <= 1000

通过代码

高赞题解

我们设 $f(i)$ 为节点 $i$ 的最短时间,然后分类讨论。

如果 $i$ 是一个叶子,那么显然 $f(i) = val(i)$。如果 $i$ 只有一个儿子,那么先要执行完儿子才轮得到自己,$f(i) = f(son(i)) + val(i)$。

如果 $i$ 有两个儿子 $l, r$,那么我们就可以考虑用双核来优化。一种最简单的优化策略是:两个子树分别使用双核跑完,然后再根节点跑。这样的时间消耗是 $f(l)+f(r) + val(i)$。

还有一种策略是:在左边花费 $x$ 时间使用双核(这里是有效使用,即两个核都必须用上,后同),在右边花费 $y$ 时间使用双核,然后在左右两棵子树一边一个核。可以看出,第三个样例使用的正是这样的策略,在根节点的右子树先花费了 3.5 的时间,然后左右两边一边一个核花费 3 时间。

那么,这种情况下,设左右子树的任务总时间和分别为 $sum(l), sum(r)$。则通过利用双核,左子树剩下的任务时间变成了 $sum(l) - 2x$,右子树剩下的任务时间变成了 $sum(r) - 2y$,然后一边一个核处理完剩下的任务所需时间为这两者的较大者。因而总时间为
$$
val(i) + x+y+\max\left\lbrace sum(l) - 2x , sum(r) - 2y \right\rbrace
$$

$$
val(i) + \max\left\lbrace sum(l) +y-x , sum(r) -(y-x)\right\rbrace
$$

$val(i)$ 的时间消耗是逃不掉的,我们考虑后面这个 $\max$ 怎样取得尽量小。设 $t=y-x$,那么后面这个 $\max$ 要取到最小当且仅当 $t^* = mid = \frac{sum(r) - sum(l)}{2}$。并且如果 $t$ 偏离 $mid$ 越远,那么这个 $\max$ 就越大。注意到 $x \in [0, sum(l) - f(l)], y \in [0, sum(r) - f(r)]$,就有 $t\in [f(l) - sum(l), sum(r) - f(r)]$。通过对 $mid$ 和这个区间位置的讨论,我们就能算出这个 $\max$ 的最小值。

最后把以上这些情况统合起来,就有下面的转移方程:
$$
f(i) = val(i) + \min\left\lbrace f(l)+ f(r), \min_{t\in [f(l) - sum(l), sum(r) - f(r)]}\max\left\lbrace sum(l) +t , sum(r) -t\right\rbrace \right\rbrace
$$
其中规定如果 $l$ 或者 $r$ 为空,对应的 $sum, f$ 均为 $0$。

时间复杂度 $O(n)$。

class Solution:
    def minimalExecTime(self, root: TreeNode) -> float:
        def dfs(cur):
            if cur == None:
                return 0, 0
            fl, sml = dfs(cur.left)
            fr, smr = dfs(cur.right)
            f, sm = cur.val + fl + fr, cur.val + sml + smr
            gl, gr = sml - fl, smr - fr
            mid = (cur.right.sm - cur.left.sm) / 2
            t = -gl if mid < -gl else (gr if mid > gr else mid)
            f = min(f, cur.val + max(sml + t, smr - t))
            return f, sm

        ans, _ = dfs(root)
        return ans

统计信息

通过次数 提交次数 AC比率
1901 3194 59.5%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
LCP 14-切分数组
下一篇:
LCP 07-传递信息
本文目录
本文目录