多因素最值问题总结

前言:这个标题是我自己取的,我们要找到一个最值,而这个值与多种因素有关,所以我把他叫做「多因素最值问题」

一般多因素的最值问题都与排序相关,关键是按什么排序,能有更好的策略。

下面我总结一些我遇到的算法思路

0X00 单因素排序

1383. 最大的团队表现值

首先发现是一个多因素最值问题,尝试两个关键字排序。

  • 如果按照 speed 排序,不好做,没思路,放弃
  • 如果按照 efficiency 排序,就可以建立一个最多 k 大小的堆,固定 e 去遍历所有的方案这样的时间复杂度是 O(nlogn)
from heapq import heappush, heappop

class Solution:
    def maxPerformance(self, n: int, speed: List[int], efficiency: List[int], k: int) -> int:
        mod = 10 ** 9 + 7
        res, minHeap, m = 0, [], [(v1, v2) for v1, v2 in zip(efficiency, speed)]
        m.sort(reverse=True)
        # print(m)
        sums = 0

        for e, s in m:
            heappush(minHeap, s)
            sums += s
            if len(minHeap) > k: sums -= heappop(minHeap)
            res = max(res, e * sums)
        
        return res % mod
        

这里有个比较坑的地方,就是如果是比较的话,中间计算过程是不能取余数的。

0X01 组合因素排序

125. 耍杂技的牛

跟上题一样同样是双因素最值问题,但是这题的最优策略不能按照单因素去排序,而是将这两个因素去组合。设一头牛 i 的重量是 w[i],强壮程度是 s[i]。

这种题你没做过是想不出来的。

所以要把这种题当成「模板题」。

首先,按照经验来看这里的「最大风险值」的计算方法不涉及 * / 在构造的时候就不用选择 * /。

我们构造按照 w[i] + s[i] 从小到大的排序的方法(按照感觉来想也是这样,重量越大,越强壮的牛放在越后面),构造牛的序列,即 w[i] + s[i] 越小的放在前面。

现在通过「微扰法」证明:

假设有这么两头牛 w[i] + s[i] > w[i+1] + s[i+1]。第 i 头牛放在了上面,假设第 i 头牛上面的重量是 w_all,那么对于这两头牛来说,我们可以列出一个表:

风险
i w_all - s[i]
i+1 w_all + w[i] - s[i+1]

「微扰法」的核心就是交换,不影响其他的值。于是我们将两者交换,得出一张新表

风险(交换前) 风险(交换后)
i w_all - s[i] w_all + w[i+1] - s[i]
i+1 w_all + w[i] - s[i+1] w_all - s[i+1]

这个题要我们求的是使最大风险值最小,现在证明交换后的最大风险值会减小:

由于 w_all + w[i] - s[i+1] > w_all - s[i] 所以交换前的最大风险值是 w_all + w[i] - s[i+1] 并且 w_all + w[i] - s[i+1] > w_all - s[i+1] 以及 w_all + w[i] - s[i+1] > w_all + w[i+1] - s[i]

所以交换后的最大风险值一定是降低的,故牛从上到下的排序一定是按 w[i] + s[i] 的升序排序的。

我们再说一个难题,谷歌 2019 年 B 轮的题目:

734. 能量石

这里有三个因素,s[i] 吃完能量石的时间, e[i] 能量石最初的能量, l[i] 能量石每秒消耗的能量。有了前一题的基础我们知道,这是一道「多因素最值问题」,和三个因素有关。

不能直接给出策略,但是我们可以来算一算(已过去 t 时间):

能量石 获得的能量(交换前) 获得的能量(交换后)
i e[i] - t * l[i] e[i] - (t + s[i+1]) * l[i]
i+1 e[i+1] - (t+s[i]) * l[i+1] e[i+1] - t * l[i+1]

计算吃这两块石头获得的能量:

获得的能量(交换前) 获得的能量(交换后)
e[i] + e[i+1] - t * (l[i] + l[i+1]) - s[i] * l[i+1] e[i] + e[i+1] - t * (l[i] + l[i+1]) - s[i+1] * l[i]

要想交换后的能量更高即:s[i+1] * l[i] < s[i] * l[i+1] => l[i+1] / s[i+1] > l[i] / s[i]

即我们的策略是:l[i] / s[i] 越大的先吃。

0X02 总结

对于多因素的最值问题,我们要做到的是:

  • 判断题目是多因素最值问题
  • 看能不能通过简单因素判断(常识)
  • 通过交换两个相邻的,且交换后要比交换前要好,判断出我们到底应该用什么因素排序

你可能感兴趣的:(多因素最值问题总结)