繁体   English   中英

寻找 f(x) = a*min(b, x) 形式的函数最大值的算法?

[英]Algorithm for finding max value of functions of the form f(x) = a*min(b, x)?

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

对于给定的x是否有已知的算法来查找哪个元组返回最大值?
我不想评估每个 function 来检查最大值,因为我会针对不同的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的某些范围,这是最好的 function。 我的意思是我不想将每个 function 与所有其他人进行比较,以找到从哪个点x' (交点)开始,我应该选择一个。

假设ab和查询的x总是非负数,每个查询可以在O(n*log(n)) O(log(n))时间内完成:

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

这是一般条件:当且仅当c > a(c*d > a*b)时,对于每个 x,A function (a, b)大于(c, d) ) 。 (这很容易证明。)

现在,我们要做的是删除存在 a (c, d)的函数(a, b)使得c > a(c*d > 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 < M ,我们删除这个元素。 因为对于我们之前处理的一些(c, d)c > ac*d > a*b ,因此(a, b)是无用的。 在这一步之后,示例数组将变为:

(2, 9)
(4, 4)

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

一旦我们去掉了所有对于任何 x 都不是最大值的函数,剩下的函数的图形将如下所示

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

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

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

使用这种方法,您可以将 map 从这个切换点切换到左侧的 function。 找到任意值的最佳 function 只需要找到下一个更高的切换点。

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

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

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

首先,让我们看一个稍微简单的问题:您有一个对(c, b)的列表,并且您想要找到具有最大值的一对c ,条件是b<=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=2 , c=6行,因为如果6<=x5<=x ,所以我们可以使用c=4行来获得更好的答案。 所以我们不妨去掉列表中类似的对,即所有c的值不是迄今为止最高的对。 因此,我们将列表缩减为:

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

鉴于此列表,在b上有一个索引,很容易找到c的最大值。 您所要做的就是在列表中找到b的最大值<=x ,然后返回c的对应值。

显然,如果您更改问题以便只需要b>=x (而不是b<=x )的值,您可以做完全相同的事情。

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

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

  1. b<=x(a, b)对中,哪一个给出f(x,a,b) = a*b的最高值?
  2. b>=x的对(a, b)中,哪一个给出f(x,a,b) = a*x的最高值?

对于 (1),简单地让每对c=a*b ,然后通过上面概述的整个索引复杂性让 go。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM