找到满足某个条件的子集

时间:2011-12-16 21:45:57

标签: c algorithm subset-sum np

我有几个数字数组(数组的每个元素只能取值0或1),如下所示

v1: 1; 0; 0; 1; 1; 
v2: 0; 1; 0; 0; 1; 
v3: 1; 1; 0; 1; 0; 
v4: 1; 0; 0; 1; 0; 
v5: 1; 1; 0; 1; 1; 
v6: 1; 1; 0; 1; 1; 

我希望找到这样的子集,当数组求和时,结果数组的单个元素是2的倍数。例如,v1 + v2 + v3得到的结果数组为2,2,0,2, 2.结果数组可以具有2的倍数值。

另一个例子:

v1: 1, 1, 1, 0, 1, 0
v2: 0, 0, 1, 0, 0, 0
v3: 1, 0, 0, 0, 0, 0
v4: 0, 0, 0, 1, 0, 0
v5: 1, 1, 0, 0, 1, 0
v6: 0, 0, 1, 1, 0, 0
v7: 1, 0, 1, 1, 0, 0

在此示例中,v1 + v2 + v5和v3 + v6 + v7是合适的答案。

我有一个强力解决方案,但我想检查是否有更有效的方法。这相当于子集求和问题吗?

1 个答案:

答案 0 :(得分:1)

您想找到所有解决方案吗?

这可以找到一个解决方案(我认为可以扩展它以找到所有解决方案)。

将每个数组表示为二进制数。

因此v1变为10011,v2变为01001等。

设*表示按位mod 2加法。

e.g。

v1*v2*v3 = 00000

所以我们的目标是找到mod 2加法全为零的数组。 让你和v成为任何二进制数。 然后u * v = 0 iff u = v。

e.g。

(v1*v2)*v3 = 0
v1*v2 = 11010 = v3.

如果你* v = w那么

u*v*v = w*v, so
u*0 = w*v,
u = w*v

所以我们可以从0开始进行反向搜索。假设最后一组数组包含v。然后v * T = 0,其中T是一些二进制数。我们有T = 0 * v。如果T是给定数组之一,那么我们就完成了。否则我们从T开始继续搜索。

这在下面正式描述。

每个州都是二进制数。

设0为初始状态。

给定的数组是状态空间的一部分,比如S。

我们的目标状态是S中的任何元素。

令T为和为0的数组的必需子集。

在每个州,让任何不在T的州都可以采取行动。

每次操作后都将数组用于T。

如果在任何非目标阶段S = T,那么就没有解决方案。

现在我们可以在这个空间运行DFS来找到解决方案。