整数数组总和为0

时间:2016-11-21 04:20:17

标签: algorithm list dynamic-programming pseudocode

我正在解决一个令我难过的问题。我们得到一个整数列表

(v1,v2,v3,... vn)

总和为 L ,我们应该找到一个动态编程算法,返回另一个数字列表

(x1,x2,x3,... xn)∈{0,1}

这样( - 1)^ x1 * v1 +( - 1)^ x2 * v2 + ... +( - 1)^ xn * vn = 0 ,并知道是否有没有这样的解决方案。对我而言,它看起来只是子集求和问题的变体,但我对如何进行记忆化感到困惑。它只是设计算法,伪代码或只是一个提示就可以了。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:1)

第一步是认识到v k 是否为负是无关紧要的。由于您可以自由地操纵输出中的符号,因此您可以假设所有输入都是非负数。

下一步是观察当你翻转v k 的符号时你的总和会发生什么:你加上-2 * v k

因此,考虑到这一点,你可以改写这样的问题:

  

给定一组非负数v 1 ... v n ,   总和为X,你能找到一个子集吗?   2 * v 1 ... 2 * v n ,以便它们总和为X

哪个是子集和问题,目标值为X

但由于任何此类子集的补充也会加起来X,这也是partition problem的情况。

答案 1 :(得分:1)

这个问题原来是你是否可以在集合S = {v1,v2,... vn}中找到分区S1 = {vi1,vi2,... vim},这样S1的总和就是等于总和(S)/ 2。 (注意,如果sum(s)%2 == 1,它将返回False)另外,我们可以假设它们都大于0

所以我们将使用动态编程来完成它。

如果{v1,v2,... vi}中的子集等于j

,则pp [i,j]为真

所以dp [i,j] = dp [i-1,j]或dp [i-vj,j-1]

我们为所有j初始化dp [0,j] = True。如果tmp< dp [tmp,j] = false 0

所以你可以解决问题。但是,时间复杂度和空间复杂性并不好。希望我们有朋友可以提供更好的解决方案。

答案 2 :(得分:-1)

我在JS中实现了一种功能和动态编程方法,如下所示。我相信如果总和是奇数,则没有解决方案。

以下代码在1-20之间生成10个随机整数的数组,然后通过动态获取子数组合来处理它。

function findPowers(a,s = a.reduce((p,c) => p+c)){
  if (s & 1) return [];
  return a.reduce((p,c,i) => p.concat(p.map((n,i,m) => [n[0]-c, i+m.length, 2*(n[0]-c) === s])),[[s,0,false]])
          .filter(f => f[2])
          .map(s => Array(a.length).fill().map((b,i) => s[1] >> i & 1));
}

var arr = Array(10).fill().map(n => ~~(Math.random()*20)+1);
console.log("Input Array:",JSON.stringify(arr));
console.log("Sum:", arr.reduce((p,c) => p+c));
console.log("Powers:",JSON.stringify(findPowers(arr)));

说明:

if (s & 1) return [];
如果总和为奇数,则

返回一个空数组。

a.reduce((p,c,i) => p.concat(p.map((n,i,m) => [n[0]-c, i+m.length, 2*(n[0]-c) === s])),[[s,0,false]])

这就是我们动态魔法发生的地方。这将通过获取已经解析的先前映射并应用当前元素来获取与前一个元素相同大小的数组并将其连接到前一个数组,从而将我们的输入数组映射到它的组合中。例如,对于[1,2,3]的输入数组,它将生成以下映射。

[ [ 6, 0, false ],
  [ 5, 1, false ],
  [ 4, 2, false ],
  [ 3, 3, true ],  // where index 3 is 011 in 2^3 items array
  [ 3, 4, true ],  // where index 4 is 010 in 2^3 items array
  [ 2, 5, false ],
  [ 1, 6, false ],
  [ 0, 7, false ] ]

其中第一项是所选元素的总和减去总和,第二项是地图中的索引,第三项是(sum of selected elements * 2)是否为输入数组的总和。第三项是冗余的,因为可以在过滤阶段检查第一项。为了清楚起见,我刚刚将它包括在内所以我们现在对true感兴趣,所以我们用

过滤掉它们
.filter(f => f[2])

然后我们需要的是要转换成二进制的索引值,这就是你所要求的。

.map(s => Array(a.length).fill().map((b,i) => s[1] >> i & 1));