这里是挑战:输入是一个包含 N 个整数的数组 X(N 的范围是 0 到 10'000,X[i] 的范围是 -100 到 100)。目标是从集合 {-1; 中找到一个由 N 个整数组成的序列 D。 1}这样
S = | sum_i (X[i] * D[i]) |
被最小化。如果我们输出整数 S(不需要明确地找到使 S 最小的序列 D),问题就解决了。
我目前的研究:
计算
M = sum_i | X[i] |
并解决以 M/2 为背包容量和 X 为项目列表的 0-1 背包问题。它给出了正确的答案,但复杂度太高。
对于范围为 0 到 N 的整数 n 和范围为 -100 到 100 的整数 r,定义
s(n, r) = 1 如果存在长度为 n 的整数序列 D 来自集合 {-1; 1} 这样 r = | sum_{i = 0 到 n} (X[i] * D[i]} |
s(n, r) = 0 否则。
则s有如下性质:
s(n, r) = s(n - 1, r - X[n]) || s(n - 1, r + X[n])
翻译成英语,如果前 n 个项目可以到达 r,那么前 (n - 1) 个项目可以到达 r - X[n] 或 r + X[n]。
根据这个属性,可以很容易地为给定范围内的任何 r 计算 s(N, r)。 当 X 按降序排序时,它提供了更多返回正确答案的机会,但在某些情况下它仍然不正确。也许可以通过为 r 提供更大的范围来纠正它,但如果有可接受的范围,我现在还不知道。
- 几何/线性代数方法:将所有可能的序列 D 视为欧几里得空间 R^k (k >= N) 中的向量,并在 R^k 的正交基中划分所有可能 D 的集合,然后将 X 写入每个新基地。但我对它能奏效的希望不大......
提示:
- N 的范围(X 的大小)远大于每个 X[i] 的范围。因此序列 X 将有重复项。
最佳答案
诀窍在于 D[i] 来自 X[i] 的相反序数排列。这通过确保最小因子乘以最大因子来最小化总和;并且每个较小的因素都与每个较大的因素归纳配对。从技术上讲,这是因为欧几里得定理。所以总和的每个乘积都有最小的质因数集。人们可能会发现 X 与冒泡排序的序数排列,它在基数为 N 的一组索引 I 上并行运行。理解背包问题的关键是更高维度的旋转对应于向量空间中的转置。
关于求解动态规划练习的算法(背包式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31424578/