我有一个带有数值的矩阵(最大尺寸为100 x 100),需要找到总计达到所需值的连接单元的最有效(最小单元格数)组。该矩阵也可以具有负单元(矩阵的内壁),该算法应该能够四处走动。在查找连接的单元时,我不需要考虑对角线单元(仅向上,向下,向左,向右)。
例如,我们有以下矩阵:
1 4 4
1 1 2
4 -1 1
如果我们正在寻找总结为:
的细胞集找到这些连接的单元格的最有效方法是什么,因为递归将在矩阵变得相对较大(如50x50)时非常慢?或者这些数据的矩阵表示不是此任务的最佳方式?
由于
答案 0 :(得分:2)
正如评论中sascha所建议的,这个问题是NP难的,因此不太可能存在有效的(多项式时间)解决方案。这是Subset Sum问题的减少,我们给出了一个目标值m和一个多个n个数字的集合,并询问是否有可能找到这些n个数的子数据总和为m:
现在任何解决方案都可以获取整个0行的值,然后在顶行中选择任何子集,因为它们都连接到第二行。因此,如果子集总和问题有解决方案,那么您的问题就有了相应的解决方案,反之亦然。
子集和是一个NP难问题,上面显示了一种解决任意子集和问题的方法,将其转化为问题的实例然后解决了这个问题,所以你的问题也必须是NP难的
我在上面假设零值可以出现在矩阵中(并且可以被选中)。如果OTOH只能选择正数,则可以调整减少量:
设z比子集和问题的所有n个输入数的绝对值之和多一个。而不是单行0值,而是创建一行z值;而不是将m作为目标,取m + nz。显然,如果SS问题有解决方案,那么我们可以通过选择SS解决方案选择的顶行中的特定数字以及底行的z值的所有n个副本来解决我们的问题。 。我现在表明另一个方向也是有效的:也就是说,如果我们可以在构造的问题实例中获得m + nz的目标,那么它必须在底行使用z值的所有n个副本,在顶行中留下总共m,对应于原始SS实例的解。
假设我们对构造的实例有一个解决方案,它击中了m + nz的目标。然后底行中的每个单元格必须是此解决方案的一部分,因为如果即使一个这样的单元格不是,那么即使我们包括,我们也无法达到nz的总和(更不用说可能更大的值m + nz) 顶行中的每个元素,因为(按设计)z> sum(顶行中的所有元素)。 (我假设m在这里是正面的。)
答案 1 :(得分:2)
为了尝试将递归次数减少到最小,我尝试使用此方法,该方法查找从短到长累加到目标的单元格序列,以便您首先找到最短的解决方案:
给定目标,例如10
和矩阵,例如
[1, 0, 1, 2, 3]
[6, 1, 4, 0, 2]
[1, 2, 4,-2, 3]
[1,-1, 2, 3, 1]
[0, 2, 3, 0, 1]
1: 6, 2: 5, 3: 4, 4: 2, 5: 0, 6: 1
6,4
6,3,1
6,2,2
6,2,1,1
6,1,1,1,1
4,4,2
4,4,1,1
4,3,3
4,3,2,1
4,3,1,1,1
4,2,2,2
4,2,2,1,1
4,2,1,1,1,1
4,1,1,1,1,1,1
3,3,3,1
3,3,2,2
3,3,2,1,1
3,3,1,1,1,1
3,2,2,2,1
3,2,2,1,1,1
3,2,1,1,1,1,1
2,2,2,2,2
2,2,2,2,1,1
2,2,2,1,1,1,1
2,2,1,1,1,1,1,1
(由于目标非常小,分区的数量不应该很大。如果目标是20,则最大分区数仅为627。)
6,4
6,3,1
6,2,2
4,4,2
4,3,3
6,2,1,1
...
如果矩阵中有零可以包含在选择中,则每当分区长度增加时(例如,当您从4,3,3
移动到6,2,1,1
时,重试用零填充的较短分区(如果可以的话)。
如果矩阵中的值非常随机,即没有专门设计使其难以找到解,那么我认为这种方法应该大大减少必要的递归次数。 (我还没有试过编码,所以我无法做出很好的估计。)