4 个答案:
答案 0 :(得分:2)
首先,正如已经确定的那样 - 问题是NP-Hard,减少了分区问题。
Reduction:
给定partition problem的实例,创建每个大小为1的列表。结果将是这个问题。
以上结论:
这个问题是NP-Hard,没有已知的多项式解。
第二,由于问题的严重性,任何指数和伪多项式解决方案都需要很长时间才能工作。
第三,它给我们留下了启发式和近似算法。
我建议采用以下方法:
规范化子列表的比例,因此所有元素都将处于相同的比例(例如,所有元素将被标准化为范围[-1,1]或者所有元素将标准化为标准normal distribution)。
创建一个新列表,其中每个元素将是规范化列表中匹配子列表的总和。
使用为子集和/分区问题开发的一些近似或启发式解决方案。
醇>
结果不是最佳的,但最佳效果在这里确实无法解决。
答案 1 :(得分:2)
根据我在原帖中的讨论中收集的内容,您不是在搜索单个分裂点,而是想要在两个集合中分配所有对,以便两个集合中的每个集合中的总和大致相等。
简而言之,我们的想法是,您可以通过随机将每对配置为左侧或右侧设置来开始。
接下来,您可以通过生成新状态
a)从左到右移动随机选择的一对,
b)移动随机选择的一对
从右到左设置,或
c)同时做两件事。
接下来,确定此新状态是好于还是差于当前状态。如果它更好,请使用它。
如果情况更糟,只有当接受概率函数接受它时才接受它,这是一个函数
最初允许使用更糟糕的状态,但随着时间的推移越来越少地支持它们(或者温度降低",在SA术语中)。
经过大量的迭代(比如100.000),你应该有一个非常好的结果。
(可选)多次重新运行此算法,因为它可能会陷入局部最优(尽管接受概率函数试图对此进行反击)。
这种方法的优点是实施起来很简单,你可以自己决定多长时间
你希望它继续寻找更好的解决方案。
答案 2 :(得分:1)
我假设我们只是在阵列中间寻找一个位置,将其分成第一和第二部分。
似乎线性算法可以做到这一点。在JavaScript中有这样的东西。
arrayLength = 2;
tolerance = 10;
// Initialize the two sums.
firstSum = [];
secondSum = [];
for (j = 0; j < arrayLength; j++)
{
firstSum[j] = 0;
secondSum[j] = 0;
for (i = 0; i < arrays.length; i++)
{
secondSum += arrays[i][j];
}
}
// Try splitting at every place in "arrays".
// Try to get the sums as close as possible.
for (i = 0; i < arrays.length; i++)
{
goodEnough = true;
for (j = 0; j < arrayLength; j++)
{
if (Math.abs(firstSum[j] - secondSum[j]) > tolerance)
goodEnough = false;
}
if (goodEnough)
{
alert("split before index " + i);
break;
}
// Update the sums for the new position.
for (j = 0; j < arrayLength; j++)
{
firstSum[j] += arrays[i][j];
secondSum[j] -= arrays[i][j];
}
}
答案 3 :(得分:0)
感谢所有答案,暴力攻击是一个好主意,NP-Hard也与此相关,但事实证明这是一个多背包问题,可以使用this pdf document解决。