我遇到了这个问题,我们需要找到可以形成n子集的总方式(其中n是用户的输入)。子集条件是:子集中的数字应该是不同的,子集中的数字应该是递减的顺序。
示例:给定n = 7,输出为4,因为可能的组合是(6,1)(5,2)(4,3)(4,2,1)。请注意,虽然(4,1,1,1)也加起来为7,但它有重复的数字。因此它不是有效的子集。
我使用具有指数复杂性的回溯方法解决了这个问题。但是,我想弄清楚如何使用Dynamic Prog解决这个问题?我能想出的最接近的是系列:对于n = 0,1,2,3,4,5,6,7,8,9,10,其输出为0,0,0,1,1,分别为2,3,4,5,7,9。但是,我无法想出一个可以用来计算f(n)的通用公式。在浏览互联网时,我在https://oeis.org/search?q=0%2C0%2C0%2C1%2C1%2C2%2C3%2C4%2C5%2C7%2C9%2C11%2C14&sort=&language=&go=Search中遇到了这种整数序列。但我无法理解他们在这里提供的公式。任何帮助,将不胜感激。任何其他提高指数复杂性的见解也值得赞赏。
答案 0 :(得分:0)
您所谓的“唯一子集生成”更为人所知的是integer partitions with distinct parts。 Mathworld在the Q function上有一个条目,它计算具有不同部分的分区数。
但,您的函数不计算普通分区(即n -> (n)
),因此您要查找的内容实际为Q(n) - 1
,生成sequence that you linked in your question } - 至少2个不同部分的分区数。 This answer关于数学的类似问题包含一个有效的Java算法,用于计算最多n = 200
的序列,可以很容易地适应更大的值。
以下是引用算法的组合解释:
让我们从{1, 2, 3}
的所有子集开始,按其总和进行分组:
index (sum) partitions count
0 () 1
1 (1) 1
2 (2) 1
3 (1+2), (3) 2
4 (1+3) 1
5 (2+3) 1
6 (1+2+3) 1
假设我们要构建一个包含{1, 2, 3, 4}
所有子集的新表。请注意,{1, 2, 3}
的每个子集也是{1, 2, 3, 4}
的子集,因此上面的每个子集都会出现在我们的新表中。实际上,我们可以将新表划分为两个大小相同的类别:不的子集包含4
,以及那些包含4
的子集。我们可以做的是从上面的表开始,复制它,然后用{1, 2, 3, 4}
“扩展”它。这是 index (sum) partitions count
0 () 1
1 (1) 1
2 (2) 1
3 (1+2), (3) 2
4 (1+3), [4] 2
5 (2+3), [1+4] 2
6 (1+2+3),[2+4] 2
7 [1+2+4],[3+4] 2
8 [1+3+4] 1
9 [2+3+4] 1
10 [1+2+3+4] 1
的表格:
4
包含4
的所有子集都用方括号括起来,它们是通过将{1,2,..,5}
添加到括号括起来的旧子集中而形成的。我们可以重复此过程并为{1,2,..,6}
,{1, 2, 3}
等构建表格。
但我们实际上并不需要存储实际的子集/分区,我们只需要每个索引/总和的计数。例如,如果只有{1, 2, 3, 4}
的表只有计数,我们可以通过从旧表中取每个(index, count)
对并添加{{1}来构建count
的计数表。 } {到index + 4
的当前计数。我们的想法是,如果有{1, 2, 3}
的两个子集总和为3
,那么将4
添加到这两个子集中的每个子集将为{{1}创建两个新的子集}。
考虑到这一点,这是这个过程的Python实现:
7
我们从def c(n):
counts = [1]
for k in range(1, n + 1):
new_counts = counts[:] + [0]*k
for index, count in enumerate(counts):
new_counts[index + k] += count
counts = new_counts
return counts
的表开始,它只有一个子集 - 空集 - 总和为零。然后我们为{}
构建表格,然后为{1}
,...构建表格,一直到{1, 2}
。完成后,我们会计算{1,2,..,n}
的每个分区,因为n
的分区不能包含大于n
的整数。
现在,我们可以对代码进行两项主要优化:
将表限制为仅包含最多n
的条目,因为这是我们感兴趣的所有内容。如果n
超过index + k
,那么我们就会忽略它。我们甚至可以预先为最终表预先分配空间,而不是在每次迭代时增加更大的表。
不是在每次迭代时从头开始构建一个新表,如果我们小心地向后迭代旧表,我们实际上可以将就地更新它而不会弄乱任何新的值。
通过这些优化,您可以有效地使用之前引用的the Mathematics answer中的相同算法,这是通过生成函数来实现的。它在n
时间内运行,仅占用O(n^2)
个空间。这是它在Python中的样子:
O(n)