7

我想出了一个新的算法来解决子集和问题,我认为它是在多项式时间内。告诉我我要么错了要么完全是个天才。

快速入门事实:

子集和问题是一个 NP 完全问题。在多项式时间内求解它意味着 P = NP。
一组长度为 N 的子集的数量为 2^N。

另一方面,长度为 N 的唯一子集的数量最大为整个集合的总和减去最小元素,或者,任何子集可能产生的和的范围在所有负元素的总和之间和所有正元素的总和,因为没有总和可能大于或小于所有正或负总和,当我们添加额外元素时,它们以线性速率增长。

这意味着随着 N 的增加,重复子集的数量呈指数增长,而唯一有用的子集的数量仅线性增加。如果可以设计一种算法来尽早删除重复的子集,我们将在多项式时间内运行。一个简单的例子很容易取自二进制文件。仅从作为 2 的幂的数字,我们可以为任何整数值创建唯一的子集。因此,任何涉及任何其他数字的子集(如果我们有 2 的所有幂)都是重复的和浪费的。通过不计算它们及其导数,我们几乎可以节省算法的所有运行时间,因为与任何整数相比,作为 2 的幂的数字都是对数出现的。

因此,我提出了一个简单的算法,该算法将删除这些重复项并省去计算它们及其所有导数的麻烦。

首先,我们将对只有 O(N log N) 的集合进行排序,并将其分成两半,正数和负数。负数的过程是相同的,所以我将只概述正数(集合现在仅表示正数,只是为了澄清)。

想象一个由 sum 索引的数组,其中包含所有可能的正边结果总和的条目(记住,这只是线性的)。当我们添加一个条目时,值是子集中的条目。就像,数组 [3] = { 1, 2 }。

一般来说,我们现在开始枚举集合中的所有子集。我们通过从一个长度的子集开始,然后添加到它们来做到这一点。当我们拥有所有独特的子集时,它们形成一个数组,我们只需按照 Horowitz/Sahni 中使用的方式迭代它们。

现在我们从“第一代”价值观开始。也就是说,如果原始数据集中没有重复的数字,则保证这些值中没有重复。也就是说,所有单值子集,以及集合的所有长度减去一个长度的子集。这些可以通过对集合求和并依次减去每个元素来轻松生成。此外,集合本身是有效的第一代总和和子集,以及子集的每个单独元素。

现在我们做第二代价值观。我们遍历数组中的每个值和每个唯一子集,如果没有,我们添加它并计算新的唯一子集。如果我们有重复,就会发生乐趣。我们将其添加到碰撞列表中。当我们添加新的子集时,我们检查它们是否在冲突列表中。我们以不太理想的(通常更大,但可以是任意的)相等子集为关键。当我们添加到子集时,如果我们会产生碰撞,我们什么也不做。当我们来添加更理想的子集时,它会错过检查并添加,生成公共子集。然后我们只是重复其他几代人。

通过以这种方式删除重复的子集,我们不必继续将重复项与集合的其余部分组合,也不必继续检查它们是否有冲突,也不必对它们求和。最重要的是,通过不创建非唯一的新子集,我们不会从它们生成新子集,我相信这可以将算法从 NP 转变为 P,因为子集的增长不再是指数级的——我们丢弃它们中的绝大多数在它们可以在下一代中“复制”并通过与其他非重复子集组合来创建更多子集之前。

我认为我没有很好地解释这一点。我有照片……它们在我的脑海里。重要的是,通过丢弃重复的子集,您几乎可以消除所有的复杂性。

例如,想象一下(因为我是手工做这个例子)一个简单的数据集,它从 -7 到 7(不是零),我们的目标是零。排序和拆分,所以我们剩下 (1, 2, 3, 4, 5, 6, 7)。总和是 28。但 2^7 是 128。所以 128 个子集适合 1 .. 28 的范围,这意味着我们事先知道 100 个集合是重复的。如果我们有 8 个,那么我们将只有 36 个插槽,但现在有 256 个子集。所以你可以很容易地看到,现在被骗的数量是 220,是以前的两倍多。

在这种情况下,第一代的值为 1, 2, 3, 4, 5, 6, 7, 28, 27, 26, 25, 24, 23, 22, 21,我们将它们映射到它们的组成部分,所以

1 = { 1 }
2 = { 2 }
...
28 = { 1, 2, 3, 4, 5, 6, 7 }
27 = { 2, 3, 4, 5, 6, 7 }
26 = { 1, 3, 4, 5, 6, 7 }
...
21 = { 1, 2, 3, 4, 5, 6 }

现在要生成新的子集,我们依次获取每个子集并将其添加到彼此的子集中,除非它们具有相互子集,例如 28 和 27 具有hueg 相互子集。因此,当我们取 1 并将其添加到 2 时,我们得到 3 = { 1, 2 } 但请等待!它已经在数组中。这意味着我们现在不会将 1 添加到任何已经包含 2 的子集中,反之亦然,因为这是 3 的子集的重复。

现在我们有

1 = { 1 }
2 = { 2 }
// Didn't add 1 to 2 to get 3 because that's a dupe
3 = { 3 } // Add 1 to 3, amagad, get a duplicate. Repeat the process.
4 = { 4 } // And again.
...
8 = { 1, 7 }

21? Already has 1 in.
...
27? We already have 28

现在我们将 2 添加到所有。

1? Existing duplicate
3? Get a new duplicate
...
9 = { 2, 7 }
10 = { 1, 2, 7 }

21? Already has 2 in
...
26? Already have 28
27? Got 2 in already.

3?

1? Existing dupe
2? Existing dupe
4? New duplicate
5? New duplicate
6? New duplicate
7? New duplicate
11 = { 1, 3, 7 }
12 = { 2, 3, 7 }
13 = { 1, 2, 3, 7 }

如您所见,即使我每次都在添加新的子集,但数量只是线性增加。

4?

1? Existing dupe
2? Existing dupe
3? Existing dupe
5? New duplicate
6? New duplicate
7? New duplicate
8? New duplicate
9? New duplicate
14 = {1, 2, 4, 7}
15 = {1, 3, 4, 7}
16 = {2, 3, 4, 7}
17 = {1, 2, 3, 4, 7}

5?

1,2,3,4 existing duplicate
6,7,8,9,10,11,12 new duplicate
18 = {1, 2, 3, 5, 7}
19 = {1, 2, 4, 5, 7}
20 = {1, 3, 4, 5, 7}
21 = new duplicate

现在我们有了范围内的每个值,所以我们停下来,将 1-28 添加到我们的列表中。对负数重复,遍历列表。

编辑:

在任何情况下,这个算法都是完全错误的。具有重复总和的子集不是出于可以从中派生子集的目的的重复,因为它们的到达方式不同——即它们不能被折叠。

4

3 回答 3

11

这并不能证明 P = NP。

您没有考虑正数为:1、2、4、8、16 等的可能性......因此当您对子集求和时不会有重复,因此它将在 O(2^N) 中运行在这种情况下时间。

您可以将此视为一种特殊情况,但对于其他类似情况,该算法仍然不是多项式。您所做的这个假设是您从子集和的 NP 完全版本转向仅解决简单(多项式时间)问题的地方:

当我们添加额外的元素时,[假设正数的总和]以线性速率增长。

在这里,您有效地假设 P(即陈述问题所需的位数)小于 N。来自维基百科的引述:

因此,如果 N 和 P 具有相同的阶数,则问题是最困难的。

如果您假设 N 和 P 的顺序相同,那么您不能假设总和会随着您添加更多元素而无限期地线性增长。随着您向集合中添加更多元素,这些元素也需要变得更大,以确保问题仍然难以解决。

如果 P(位值的个数)是一个小的固定数,那么有动态规划算法可以精确地解决它。

您重新发现了其中一种算法。这是一项不错的工作,但它不是新事物,也不能证明 P = NP。对不起!

于 2010-06-26T23:07:43.197 回答
6

死机甲,

你发帖已经快半年了,但我还是会回答的。

马克拜尔斯写了大部分应该写的东西。

该算法是已知的。

这种算法称为生成函数算法或简称为动态规划算法。

您的算法具有非常重要的特征,即所谓的伪多项式复杂性。

传统的复杂性是问题大小的函数。就传统复杂度而言,您的算法具有 O(2^n) 悲观复杂度(即前面提到的数字 1,2,4,...)

您的算法算法的复杂性可以替代地表示为问题大小和问题中某些数字大小的函数。对于您的算法,它类似于 O(nw) ,其中 w 是不同和的数量。

这是伪多项式复杂度。这是一个非常重要的功能。这种算法可以解决许多现实世界的问题实例,尽管问题的复杂性等级很高。

Horowitz 和 Sahni 算法的悲观复杂度为 O(2^N/2)。这不是比您的算法好两倍,而是比您的算法好 2^N/2 倍。Greg 可能的意思是 Horowitz 和 Sahni 算法可以解决两倍大的问题实例(在子集总和中有两倍的数字)

这在理论上是正确的,但实际上 Horowitz 和 Sahni 可以解决(在家用计算机上)大约 60 个数字的实例,而与您的算法类似的算法甚至可以处理 1000 个数字的实例(前提是这些数字本身不是太大)

事实上,这两种算法甚至可以混合使用,即你的算法和 Horowitz 和 Sahni 算法。这样的解决方案同时具有 O(2^n/2) 的伪多项式复杂度和悲观复杂度。

一个训练有素的计算机科学家可以通过生成函数理论构造出像你这样的算法。

受过训练和未受过训练都可以按照您的方式思考。

不一定要以“它知道吗?”来思考。您可以自己发明这种算法对您来说应该很重要。这意味着您可能可以自己发明其他重要的算法,并且有一天可能会发明一种不为人知的算法。了解该领域的当前进展以及文献中的内容会有所帮助。否则,您将继续重新发明轮子。

当我回到高中时,我重新发明了 Dijkstra 算法。我的版本非常复杂,因为我对数据结构一无所知。无论如何,我仍然为自己感到骄傲。

如果您仍在学习,请注意生成函数理论。

您可能还想在 wiki 上查看:

伪多项式时间弱NP完全强NP完全生成函数

美利

于 2010-12-22T10:17:38.033 回答
1

这意味着随着 N 的增加,重复子集的数量呈指数增长,而唯一有用的子集的数量仅线性增加。

不一定 - 重复子集总和的数量也取决于集合中最接近零的数字的值(即到零的最小距离越大 - 集合的重复子集总和越少)。

一般来说,我们现在开始枚举集合中的所有子集。

不幸的是,枚举集合子集的所有总和需要执行指数数量的加法运算(在您的示例中为 2^7 或 128)。否则,算法将如何确定唯一的和是什么?因此,尽管第一步之后的步骤很可能具有多项式运行时间,但整个算法具有指数复杂性(因为算法仅与其最慢的部分一样快)。

顺便说一句,用于解决子集和问题的最著名算法(Horowitz 和 Sahni,1974 年)具有 O(2^N/2) 复杂度 - 这使得它的速度大约是该算法的两倍。

于 2010-07-20T22:30:57.697 回答