【问题标题】:Algorithm for finding max value of functions of the form f(x) = a*min(b, x)?查找 f(x) = a*min(b, x) 形式的函数最大值的算法?
【发布时间】:2021-04-03 22:36:21
【问题描述】:

我有一组元组 (a, b)a > 0b > 0
每个元组代表一个函数f,使得f(x, a, b) = a * min(b, x)

对于给定的x,是否有已知算法可以找到哪个元组返回最大值?
我不想评估每个函数来检查最大值,因为我会针对不同的x 查询这个数组任意次数。

例子:

array = [ (1, 10), (2, 3) ]
x < 6 -> choose (2, 3)
x = 6 (intersection point) -> either (1, 10) or (2, 3) doesn't matter
x > 6 -> choose (1, 10)

所以问题是这些元组可以按ab 排序。但是它们之间可能有很多交叉点(如果我们将它们可视化为图形)。所以我想避免任何 O(n^2) 排序算法来检查x 的某些范围,这是最好的功能。我的意思是我不想将每个函数与所有其他函数进行比较,以找出从哪个点x'(交点)和我应该选择一个而不是另一个。

【问题讨论】:

  • “因为我会查询这个数组任意次数的不同” - 你可以记住结果。
  • f(x) = a * min( b, x )实际 函数定义吗?
  • f(x) 实际上是f( x, a, b ),因为ab 也是参数,即使它们是常量。只是说。如果您使用柯里化,则 @​​987654338@ 返回一个函数,而不是一个值。
  • @Dai 我编辑了我的帖子并添加了ab 作为f 的参数。
  • 参数ab的域是什么?总是整数?总是积极的?

标签: algorithm sorting optimization convex-hull convex-optimization


【解决方案1】:

假设a's、b's 和查询的x's 总是非负数,则每个查询都可以在O(log(n)) 时间在O(n*log(n)) 预处理步骤之后完成:

预处理步骤消除了这些严格受他人支配的功能。例如,对于每个 x,(5, 10) 都大于 (1, 1)。 (所以,如果数组中有(5, 10),那么我们可以删除(1, 1),因为它永远不会是任何x 的最大值。)

这是一般条件:当且仅当c &gt; a(c*d &gt; a*b) 时,函数(a, b) 对于每个x 都大于(c, d)。 (这很容易证明。)

现在,我们要做的是删除存在(c, d) 的函数(a, b),例如c &gt; a(c*d &gt; a*b)。这可以在 O(n*log(n)) 时间内完成:

1 - 按字典顺序对元组进行排序。我的意思是按字典顺序首先比较它们的第一个坐标,如果它们相等,然后比较第二个坐标。例如,排序后的数组可能如下所示:

(1, 5)
(1, 17)
(2, 9)
(4, 3)
(4, 4)

2 - 以相反的顺序遍历已排序的数组,并跟踪您目前遇到的最大值 a*b。我们称这个值为M。现在,假设我们在循环中处理的元素是(a, b)。如果a*b &lt; M,我们删除这个元素。因为对于我们之前处理的一些(c, d)c &gt; ac*d &gt; a*b,因此(a, b) 是无用的。经过这一步,示例数组将变为:

(2, 9)
(4, 4)

(4, 3) 被删除,因为它被 (4, 4) 支配。 (1, 17)(1, 5) 被删除,因为它们被 (2, 9) 支配。

一旦我们去掉了所有对于任何 x 都不是最大值的函数,其余函数的图形将看起来像 this

如图所示,从与前一个函数相交的点到与后一个函数相交的点,每个函数都是最大值。对于上面的示例,(4, 4)(2, 9)x = 8 处相交。所以(4, 4) 是直到x = 8 的最大值,在那之后,(2, 9) 是最大值。 我们要计算数组中连续函数相交的点,这样对于给定的 x,我们可以对这些点进行二分搜索,找出哪个函数返回最大值。

【讨论】:

    【解决方案2】:

    效率的关键是避免无用的工作。如果您想象一棵决策树,那么修剪分支是一个经常用于此的术语。

    对于您的情况,决策基于在两个函数(或参数元组)之间进行选择。为了选择这两个函数中的任何一个,您只需确定它们为您提供相同值的值x。其中一个对于较小的值表现更好,一个对于较大的值。另外,不要忘记这部分,它可能是一个函数总是比另一个执行得更好。在这种情况下,可以完全删除表现较差的那个(另见上文,避免无用的工作!)。

    使用这种方法,您可以从这个切换点映射到左侧的函数。找到任意值的最优函数只需要找到下一个更高的切换点。

    顺便说一句:确保你有单元测试。这些东西很繁琐,尤其是浮点值和舍入错误,所以你要确保你可以运行越来越多的测试套件,以确保一个小错误修复不会破坏其他地方的东西。

    【讨论】:

      【解决方案3】:

      我认为您应该先根据“b”对数组进行排序,然后再根据“a”排序。现在对于每个 x 只需使用二进制搜索并找到 min(b,x) 将根据值仅给出 b 或 x 的位置。因此,从那时起,如果 x 很小,那么 b 的所有即将到来的值然后将元组作为 t1 并且您可以使用该函数计算值,并且对于 b 的值将小于 x 您必须遍历。我不确定,但这是我能想到的。

      【讨论】:

        【解决方案4】:

        数据预处理后,可以及时计算出这个最大值O(log(n)),其中n是元组(a, b)的个数。

        首先,我们来看一个稍微简单的问题:你有一个(c, b)的对列表,你想找到c的最大值,条件是b&lt;=x,你想要为x 的不同值多次执行此操作。例如以下列表:

         c   b
        ------
        11  16
         8  12
         2   6
         7   9
         6  13
         4   5
        

        有了这个列表,如果你用x=10问,c的可用值是2、7和4,最大值是7。

        让我们按照b对列表进行排序:

         c   b
        ------
         4   5
         2   6
         7   9
         8  12
         6  13
        11  16
        

        当然,此列表中的某些值永远无法给出答案。例如,我们永远不能在答案中使用b=2c=6 行,因为如果6&lt;=x5&lt;=x,所以我们可以使用c=4 行来获得更好的答案。所以我们不妨在列表中去掉类似的对,即到目前为止c 的值不是最高的所有对。因此,我们将列表缩减为:

         c   b
        ------
         4   5
         7   9
         8  12
        11  16
        

        鉴于此列表,索引为b,很容易找到c 的最大值。只需在&lt;=x列表中找到b的最大值,然后返回c的对应值。

        显然,如果您更改问题以便只需要带有b&gt;=x(而不是b&lt;=x)的值,您可以做同样的事情。

        没错。那么这对您提出的问题有何帮助?

        对于给定的x 值,您可以将问题拆分为 2 个问题。如果你能回答这两个问题,那么你就可以回答整个问题:

        1. (a, b)b&lt;=x 对中,哪一对给出的f(x,a,b) = a*b 的值最高?
        2. (a, b)b&gt;=x 的对中,哪一对的f(x,a,b) = a*x 的值最高?

        对于 (1),只需为每一对设置 c=a*b,然后遍历上面概述的整个索引复杂性。

        对于 (2),让 c=a 并执行上面的索引操作,但翻转以执行 b&gt;=x 而不是 b&lt;=x;当你得到a 的答案时,别忘了将它乘以x

        【讨论】:

        • 为什么 b 的最大值使得 b
        • @but-为什么我不确定你在问什么。您制作了 2 个索引列表:一个可用于查找 f(x,a,b) 的最大值和 b&lt;=x,另一个可用于查找 f(x,a,b) 的最大值和 b&gt;=x。对于给定的x 值,您进行计算以找到b&lt;=x 的最大可能f(x,a,b),以及b&gt;=x 的最大f(x,a,b)。这两个数字中较大的一个就是您要寻找的最终答案。
        猜你喜欢
        • 2023-03-27
        • 2022-11-20
        • 2020-07-12
        • 1970-01-01
        • 2016-10-27
        • 1970-01-01
        • 2020-03-15
        • 2017-11-03
        • 2022-04-11
        相关资源
        最近更新 更多