3-分区问题
这是另一个动态规划问题(Vazirani ch6)
考虑以下 3-PARTITION 问题。给定整数 a1...an,我们 想确定是否是 可以将 {1...n} 划分为 三个不相交的子集 I, J, K 这样 那个
总和(I) = 总和(J) = 总和(K) = 1/3*总和(全部)
例如,对于输入 (1; 2; 3; 4; 4; 5; 8)答案是肯定的,因为有 是分区 (1; 8), (4; 5), (2; 3; 4)。另一方面,对于输入 (2; 2; 3; 5) 答案是否定的。设计 并分析动态规划 运行于 3-PARTITION 的算法 n 和 (Sum a_i) 的时间多项式
我该如何解决这个问题?我知道2分区,但还是无法解决
here is another dynamic programming question (Vazirani ch6)
Consider the following 3-PARTITION
problem. Given integers a1...an, we
want to determine whether it is
possible to partition of {1...n} into
three disjoint subsets I, J, K such
thatsum(I) = sum(J) = sum(K) = 1/3*sum(ALL)
For example, for input (1; 2; 3; 4; 4;
5; 8) the answer is yes, because there
is the partition (1; 8), (4; 5), (2;
3; 4). On the other hand, for input
(2; 2; 3; 5) the answer is no. Devise
and analyze a dynamic programming
algorithm for 3-PARTITION that runs in
time poly- nomial in n and (Sum a_i)
How can I solve this problem? I know 2-partition but still can't solve it
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
很容易将 2 组解决方案推广到 3 组情况。
在原始版本中,您创建布尔
sums
数组,其中sums[i]
告诉 sumi
是否可以通过集合中的数字达到,或者不是。然后,一旦创建了数组,您只需查看sums[TOTAL/2]
是否为true
即可。既然你说你已经知道旧版本,我只会描述它们之间的区别。
在 3 分区的情况下,您保留布尔
sums
数组,其中sums[i][j]
告诉第一组是否可以有总和i
第二个 - sumj
。然后,一旦创建了数组,您只需查看 sums[TOTAL/3][TOTAL/3] 是否为true
。如果原始复杂度为
O(TOTAL*n)
,则此处为O(TOTAL^2*n)
。从最严格的意义上来说,它可能不是多项式,但原始版本也不是严格的多项式:)
It's easy to generalize 2-sets solution for 3-sets case.
In original version, you create array of boolean
sums
wheresums[i]
tells whether sumi
can be reached with numbers from the set, or not. Then, once array is created, you just see ifsums[TOTAL/2]
istrue
or not.Since you said you know old version already, I'll describe only difference between them.
In 3-partition case, you keep array of boolean
sums
, wheresums[i][j]
tells whether first set can have sumi
and second - sumj
. Then, once array is created, you just see ifsums[TOTAL/3][TOTAL/3]
istrue
or not.If original complexity is
O(TOTAL*n)
, here it'sO(TOTAL^2*n)
.It may not be polynomial in the strictest sense of the word, but then original version isn't strictly polynomial too :)
我认为通过归约,它是这样的:
将2分区减少到3分区:
设S为原始集合,A为其总和,然后令S'=union({A/2},S)。
因此,对集合 S' 执行 3 分区会产生三个集合 X、Y、Z。
X、Y、Z中,其中之一必须是{A/2},假设它是集合Z,则X和Y是2分区。
S' 上 3 分区的见证人就是 S 上 2 分区的见证人,因此 2 分区减少为 3 分区。
I think by reduction it goes like this:
Reducing 2-partition to 3-partition:
Let S be the original set, and A be its total sum, then let S'=union({A/2},S).
Hence, perform a 3-partition on the set S' yields three sets X, Y, Z.
Among X, Y, Z, one of them must be {A/2}, say it's set Z, then X and Y is a 2-partition.
The witnesses of 3-partition on S' is the witnesses of 2-partition on S, thus 2-partition reduces to 3-partition.
如果这个问题是可以解决的;那么
sum(ALL)/3
必须是一个整数。任何解都必须具有SUM(J) + SUM(K) = SUM(I) + sum(ALL)/3
。这代表了concat(ALL, {sum(ALL)/3})
上的 2 分区问题的解决方案。您说您有一个 2 分区实现:用它来解决那个问题。然后(至少)两个分区之一将包含数字
sum(ALL)/3
- 从该分区中删除该数字,您就找到了I
。对于另一个分区,再次运行 2-partition,将J
与K
分开;毕竟,J
和K
本身的总和必须相等。编辑:这个解决方案可能是不正确的 - 连接集的 2 分区将有多个解决方案(I、J、K 至少各有一个) - 但是,如果还有其他解,那么“另一边”可能不是由 I、J、K 中的两个并集组成,并且可能根本不可分割。我担心你需要真正思考:-)。
尝试 2: 迭代多重集,维护以下映射:
R(i,j,k) :: Boolean
表示以下事实:到当前迭代为止,数字允许分为三个多重集,其总和为i
、j
、k
。即,对于任何R(i,j,k)
和下一个状态R'
中的下一个数字n
,它保持R '(i+n,j,k)
和R'(i,j+n,k)
和R'(i,j,k+n)
代码>.请注意,复杂性(根据练习大小)取决于输入数字的大小;这是一个伪多项式时间算法。 Nikita 的解决方案在概念上类似,但比该解决方案更有效,因为它不跟踪第三组的总和:这是不必要的,因为您可以轻松计算它。If this problem is to be solvable; then
sum(ALL)/3
must be an integer. Any solution must haveSUM(J) + SUM(K) = SUM(I) + sum(ALL)/3
. This represents a solution to the 2-partition problem overconcat(ALL, {sum(ALL)/3})
.You say you have a 2-partition implementation: use it to solve that problem. Then (at least) one of the two partitions will contain the number
sum(ALL)/3
- remove the number from that partion, and you've foundI
. For the other partition, run 2-partition again, to splitJ
fromK
; after all,J
andK
must be equal in sum themselves.Edit: This solution is probably incorrect - the 2-partition of the concatenated set will have several solutions (at least one for each of I, J, K) - however, if there are other solutions, then the "other side" may not consist of the union of two of I, J, K, and may not be splittable at all. You'll need to actually think, I fear :-).
Try 2: Iterate over the multiset, maintaining the following map:
R(i,j,k) :: Boolean
which represents the fact whether up to the current iteration the numbers permit division into three multisets that have sumsi
,j
,k
. I.e., for anyR(i,j,k)
and next numbern
in the next stateR'
it holds thatR'(i+n,j,k)
andR'(i,j+n,k)
andR'(i,j,k+n)
. Note that the complexity (as per the excersize) depends on the magnitude of the input numbers; this is a pseudo-polynomialtime algorithm. Nikita's solution is conceptually similar but more efficient than this solution since it doesn't track the third set's sum: that's unnecessary since you can trivially compute it.正如我在另一个类似问题中回答过的那样,C++ 实现看起来像这样:
As I have answered in same another question like this, the C++ implementation would look something like this:
假设您想要将
$X = {x_1, ..., x_n}$
集合划分为$k$
分区。创建一个$n\timesk$表。假设成本
$M[i,j]$
是 $j$ 分区中$i$
元素的最大总和。只需递归地使用以下最优标准来填充它:Let's say you want to partition the set
$X = {x_1, ..., x_n}$
in$k$
partitions.Create a $ n \times k $ table. Assume the cost
$M[i,j]$
be the maximum sum of$i$
elements in $j$ partitions. Just recursively use the following optimality criterion to fill it:创建一个三维数组,其中 size 是元素数量,part 等于所有元素的总和除以 3。因此 array[seq][ 的每个单元格sum1][sum2] 告诉您是否可以使用给定数组 A[] 中的 max seq 元素创建 sum1 和 sum2。因此,计算数组的所有值,结果将在元胞数组中[使用所有元素][所有元素的总和/ 3][所有元素的总和/ 3],如果您可以创建两个集合而不交叉等于sum/3,则有将进行第三组。
检查逻辑:排除A[seq]元素到第三个和(不存储),检查没有元素的单元格是否有相同的两个和; OR 包含到 sum1 - 如果可以得到两个没有 seq 元素的集合,其中 sum1 小于元素 seq A[seq] 的值,并且 sum2 不变;或者像以前一样包括到 sum2 检查。
Create a three dimensional array, where size is count of elements, and part is equal to to sum of all elements divided by 3. So each cell of array[seq][sum1][sum2] tells can you create sum1 and sum2 using max seq elements from given array A[] or not. So compute all values of array, result will be in cell array[using all elements][sum of all element / 3][sum of all elements / 3], if you can create two sets without crossing equal to sum/3, there will be third set.
Logic of checking: exlude A[seq] element to third sum(not stored), check cell without element if it has same two sums; OR include to sum1 - if it is possible to get two sets without seq element, where sum1 is smaller by value of element seq A[seq], and sum2 isn't changed; OR include to sum2 check like previous.
C++ 中的另一个示例(基于之前的答案):
Another example in C++ (based on the previous answers):
你真的想要 Korf 的完整 Karmarkar-Karp 算法 (http:// /ac.els-cdn.com/S0004370298000861/1-s2.0-S0004370298000861-main.pdf,http://ijcai.org/papers09/Papers/IJCAI09-096.pdf)。给出了三分区的概括。考虑到问题的复杂性,该算法的速度快得惊人,但需要一些实现。
KK的本质思想是保证大小相似的大块出现在不同的分区中。一组对块进行分组,然后可以将其视为大小等于可以正常放置的大小差异的较小块:通过递归执行此操作,最终会得到易于放置的小块。然后对块组进行两种着色,以确保处理相反的放置。扩展到 3 分区有点复杂。 Korf扩展是使用KK顺序的深度优先搜索来找到所有可能的解决方案或快速找到解决方案。
You really want Korf's Complete Karmarkar-Karp algorithm (http://ac.els-cdn.com/S0004370298000861/1-s2.0-S0004370298000861-main.pdf, http://ijcai.org/papers09/Papers/IJCAI09-096.pdf). A generalization to three-partitioning is given. The algorithm is surprisingly fast given the complexity of the problem, but requires some implementation.
The essential idea of KK is to ensure that large blocks of similar size appear in different partitions. One groups pairs of blocks, which can then be treated as a smaller block of size equal to the difference in sizes that can be placed as normal: by doing this recursively, one ends up with small blocks that are easy to place. One then does a two-coloring of the block groups to ensure that the opposite placements are handled. The extension to 3-partition is a bit complicated. The Korf extension is to use depth-first search in KK order to find all possible solutions or to find a solution quickly.