某个函数的最大值

问题描述

给定一个 n 实数数组 {a0,a1,...,a(n-1)}一个具有 n 位的二进制数,函数 f(x)(其中 x 是二进制数)计算:

f(x)= Sum{from i = 0 to i = n-1} (ai) * bit(x,i)

其中 bit(x,i) 表示二进制数 i 的第 x 位。

例如:a:={12,10},f(01) = 12 * 0 + 10 * 1 = 10

输入是数字数组 n、数字数组 a 和二进制数 t 的大小。

问题是找到 x,它为我们提供了 f(x) 的最大值并且小于 t

示例:

input:
n=5
a=5 8 -3 6 9
t=10111

output:
x=01011

我的解决方案是从 1 开始所有正数和 0 开始所有负数,然后尝试减少数字直到它小于给定的数字。但这需要很多时间,我想找到一个更聪明的解决方案。

解决方法

我认为,对于任何二进制数 t,您只需递归地考虑每个最高有效位的两个选项:它自己(没有 a 中的负数),以及比它的最重要位少一个有效位(不含 a 中的负数)。

对于二进制数,例如 4 = 100,其最高有效位(在本例中为 4s 位)将始终大于所有其他小于它的位,例如 3 = 011。因此,当考虑任意目标二进制数 t 时,它的形式为

  k     l
/---\ /---\
0...010...01(0|1)*

第一个之前的 k 零永远不会参与解决方案,因为所有小于 xt 在这些位置也会有零。在 MSB 之后但在下一个最大的 l 之前的 1 零都可供您使用。所以你可以考虑

  k     l
/---\ /---\
0...001...111*

(排除负数,因为它们将始终被排除。)

您可以继续对 1 中的每个 t 进行比较。让我们看一些例子:

a:={1,1,5000,4999},t:=0010,here you use x:=t
a:={1,4999,5000},here you use x:=0001
a:={5000,1},t:=1000,here you use x:=0111
a:={5000,4000,4000},t:=1010,2000,2000},here you use x:=1001

在每个示例中,我们只考虑 t 中的 MSB,或者比 t 中的 MSB 少一个。

所以您的运行时复杂度是 O(k),其中 k 是 t 中的 1 的数量。 O(n) 的最坏情况复杂度,其中 n 是 a 的大小(t 都是 1)。

,

这是我的方法,大量评论是尽可能对初学者友好。 我没有尝试“改进”原始位图,而是从 0 开始并从与最高数组值匹配的位开始一个一个地打开位(在您的示例中为“1”位,因为它与数组中的第 9 个)一直到最低的一个,除非数组值为负或生成的位图会超过原始位图。

应该是 O(n * log(n)),n 是数组的长度,因为我对数组进行了排序。

def bestBitMap(array,original):

    # Empty mask (i.e 00000) in integer form.
    result = 0

    # Original mask in integer form.
    original = int(original,2)

    # We iterate the array by its indexes from highest to lowest value.
    #(i.e in [5,8,-3,6,9] i starts at index 4 (value 9),then 1 (value 8),then 3 (value 6),and so on).
    sorted_indexes = sorted(range(len(array)),key = lambda e: array[e],reverse=True)
    for i in sorted_indexes:

        # mask for the bit we may turn on with a bitwise OR operation.
        # Bits go from right to left so we invert the index.
        mask = (2 ** (len(array) - i - 1))

        # Here we check both if the number is positive and if the current result masked by
        # the current mask wouldn't surpass the original. 
        if array[i] > 0 and ((result + mask) <= original):
            result += mask

    # We return the results in binary format
    return ("{0:0" + str(len(array)) + "b}").format(result)