给定大小的非相邻集的数量
Posted
技术标签:
【中文标题】给定大小的非相邻集的数量【英文标题】:Number of non-adjacent sets of a given size 【发布时间】:2012-02-15 20:04:08 【问题描述】:如果给定集合L=1,2,3,...,N
和整数k
,是否可以有效地计算大小为k
的“非相邻”子集的数量?如果S
中的每个x
不相邻,则子集S
不相邻,x-1
和x+1
都不在S
中。
例如,对于 L=1,2,3,4
和 k=2
,答案是 3,因为我们有
1,3,1,4,2,4
。对于k=3
,答案为零。
一种方法是生成所有大小为 2 的非相邻子集,然后尝试所有可能的并集(因为非相邻集具有其所有子集都不相邻的属性),但这让我很震惊浪费,并且可能有一个优雅而有效的解决方案。
【问题讨论】:
【参考方案1】:这样想:如果您知道集合L'=1, 2, 3, ..., N - 1
的答案是什么,您能否使用该信息来构建集合L
的答案?
这个想法是,当您将N
添加到L'
时,新的解决方案由L'
可用的所有子集加上小于或等于@987654327 的L'
的每个元素的1 个新子集组成@,所以如果L'
的解决方案的大小为V'
,那么V
L
的解决方案将是V = V' + (N - 2*(k - 1))
如果你再计算一下,你会发现解可以表示为第一个N - 2k + 2
自然整数之和。
关于小于或等于N - 2*(k - 1)
部分,被添加的新数字N
只会添加到最终数字小于或等于该表达式结果的子集中,因为其中必须有k
元素正在构建的新子集(包括数字 N
本身,因此需要更多 k - 1
)彼此之间至少间隔 2 个数字,这使得 2*(k - 1)
与数字 N
的距离为所以表达。
【讨论】:
感谢您的回复。我不遵循关于“小于或等于 N - 2*(k - 1)”的部分。但是您的最终公式似乎是错误的:N=4 和 k=2 的 N-k-1 等于 4-2-1=1,因此您将返回 1 而不是 3。 对不起,我在计算公式时出错了。应该是现在 我还添加了您不理解的解释。希望它有所帮助:) 感谢您添加的信息!不过,这对我来说似乎仍然不正确。取 N=6 和 k=3。那么我们应该有集合 135、136、146 和 246,即答案 4。但是公式 N-2k+2=2 得出 1+2=3。 您的回答启发我看到了一个看似正确且相当有效的解决方案。用 #(m,n) 表示 1,...,n 中大小为 m 的非相邻子集的数量。那么以下成立:#(m,n)=#(m,n-1)+#(m-1,n-1)。当然,像您这样的解决方案会更好,因为更容易计算。【参考方案2】:这可能与 Win32 的解决方案相同,但我不确定。所以我单独发布。
取 S(n) 为大小为 n 的连续序列的非相邻子集的数量(即 S(n) 是您正在寻找的解决方案)。
让我们计算 S(n+1),当我们向序列中添加一个元素时的值。当我们添加一个元素 k 时,我们会增加该序列的非相邻子集的数量。我们可以将这些新子集分为以下几类。
仅包含我们添加的新元素的子集。只有其中之一 (k)。 我们可以添加 k 并且仍然保留我们的非相邻标准(加上 k)的子集。我们可以将 k 添加到任何不包含 k-1 的子集,同时保持非邻接。另一种说法是,我们可以将 k 添加到最多包含 k-2 的子集中。最多包含 k-2 个子集的个数等于 S(n-1)。所以当我们将 k 添加到我们的序列时,新的不相邻子集的数量是 1 + S(n-1)。换句话说,1 + S(n-1) = S(n+1) - S(n)。我们可以重新排列这个公式,得到 S(n+1) = 1 + S(n-1) + S(n)。
递归解决方案不是很有帮助,因此我们可以尝试对其进行概括。我不擅长这一步,但是Wolfram|Alpha is,我们发现通式等于以下。
S(n) = 1/2 * (3 * Fib(n) + Lucas(n) - 2)以下是一些示例数据点。
n | S(n)
0 | 0
1 | 1
2 | 2
3 | 4
4 | 7
5 | 12
6 | 20
7 | 33
8 | 54
9 | 88
【讨论】:
我现在意识到我完全忘记了解决一组特定基数的问题。也许它仍然有用。 感谢您的回复和其他信息——我很难理解您为什么以这种方式使用 k :) 我同意您的推理,并认为总和是正确的基数。我不知道 WolframAlpha 解决了这样的系统。【参考方案3】:用S(m,n)
表示1,...,n
中大小为m
的不相邻子集的数量。那么以下成立:
S(m,n) = S(m,n-1) + S(m-1,n-2)
所以可以通过O(Nk)
中的DP解决它,通过添加边界条件
S(1,n) = n
S(m,1) = I(m==1)
S(m,2) = 2*I(m==1)
其中I()
是指标函数。
【讨论】:
【参考方案4】:让:
S(n,k)
是大小为k
的1,...n
的不相邻子集的集合
显然,S(n-1,k)
是一组大小为 k
的不相邻子集,它是 S(n,k)
的子集。
另外,S(n-2,k-1)
是一组大小为k-1
的不相邻子集,并且这些子集都不包括n-1
。因此,我们可以安全地将n
添加到每个子集中,以获得大小为k
的子集。而且由于它们不包括n-1
(与n
唯一相邻的元素),它们也是不相邻的。
因此:
S(n,k) = S(n-1,k) U (n X S(n-2,k-1))
使用一些实数,让我们尝试求解S(6,3)
。
S(6,3) = S(5,3) U (6 X S(4,2))
S(5,3) = 1,3,5 # Only one solution
S(4,2) = S(3,2) U (4 X S(2,1))
S(3,2) = 1,3 # Only one solution
S(2,1) = 1 2 # All sets of 1 element are non-adjacent
4 X S(2,1) = 1,4 2,4 # Add 4 to each
S(4,2) = 1,3 1,4 2,4
6 X S(4,2) = 1,3,6 1,4,6 2,4,6
S(6,3) = 1,3,5 1,3,6 1,4,6 2,4,6
哪个符合你的答案。
现在,计算数字:
设
N(n,k)
为S(n,k)
中的元素个数
然后:
N(n,k) = N(n-1,k) + N(n-2,k-1)
我还没有确定封闭形式,但这里有一些计算值:
n k=1 k=2 k=3 k=4 k=5 k=6 k=7 k=8 k=9 k=10 k=11 k=12 k=13
1 1
2 2
3 3 1
4 4 3
5 5 6 1
6 6 10 4
7 7 15 10 1
8 8 21 20 5
9 9 28 35 15 1
10 10 36 56 35 6
11 11 45 84 70 21 1
12 12 55 120 126 56 7
13 13 66 165 210 126 28 1
14 14 78 220 330 252 84 8
15 15 91 286 495 462 210 36 1
16 16 105 364 715 792 462 120 9
17 17 120 455 1001 1287 924 330 45 1
18 18 136 560 1365 2002 1716 792 165 10
19 19 153 680 1820 3003 3003 1716 495 55 1
20 20 171 816 2380 4368 5005 3432 1287 220 11
21 21 190 969 3060 6188 8008 6435 3003 715 66 1
22 22 210 1140 3876 8568 12376 11440 6435 2002 286 12
23 23 231 1330 4845 11628 18564 19448 12870 5005 1001 78 1
24 24 253 1540 5985 15504 27132 31824 24310 11440 3003 364 13
25 25 276 1771 7315 20349 38760 50388 43758 24310 8008 1365 91 1
26 26 300 2024 8855 26334 54264 77520 75582 48620 19448 4368 455 14
【讨论】:
以上是关于给定大小的非相邻集的数量的主要内容,如果未能解决你的问题,请参考以下文章
Python:优化函数以查找给定候选项集的大小为 k 的频繁项集