更新: 组合和无人值守最终是我所需要的。 以下链接帮助了很多:
http://msdn.microsoft.com/en-us/library/aa289166(v=vs.71).aspx
http://www.codeproject.com/Articles/21335/Combinations-in-C-Part-2
问题
给出N个符号的列表,说{0,1,2,3,4 ...}
和NCr这些组合
例如。 NC3将生成:
0 1 2
0 1 3
0 1 4
...
...
1 2 3
1 2 4
etc...
对于第i个组合(i = [1 .. NCr])我想确定一个符号是否是其中的一部分。
Func(N,r,i,s)=真/假或0/1
例如。从上面继续
第一个组合包含0 1 2但不包含3
F(N,3,1,"0") = TRUE
F(N,3,1,"1") = TRUE
F(N,3,1,"2") = TRUE
F(N,3,1,"3") = FALSE
可能有帮助或相关的当前方法和措施。
与矩阵的关系
对于r = 2,例如。在图4C2中,组合是2D矩阵的上半部分(或下半部分)
1,2 1,3 1,4
----2,3 2,4
--------3,4
对于r = 3,它是3D矩阵或立方体的一角 对于r = 4它是4D矩阵的“角”,依此类推。
另一种关系
理想情况下,解决方案的形式类似于以下答案:
Calculate Combination based on position
长度为r的组合列表中的第n个组合(允许重复),可以计算第i个符号
使用整数除法和余数:
n / r ^ i%r =(0表示第0个符号,1表示第1个符号....等)
例如对于3个符号的第6个梳子,第0个第1个和第2个符号是:
i = 0 => 6 / 3^0 % 3 = 0
i = 1 => 6 / 3^1 % 3 = 2
i = 2 => 6 / 3^2 % 3 = 0
第6梳子将是0 2 0
我需要类似的东西,但不允许重复。
感谢您关注此问题:] 凯文。
答案 0 :(得分:1)
我相信您的问题是unranking combinations或子集的问题。
我将从包Combinatorica向您提供Mathematica中的实现,但上面的Google链接可能是一个更好的起点,除非您熟悉语义。
UnrankKSubset::usage = "UnrankKSubset[m, k, l] gives the mth k-subset of set l, listed in lexicographic order."
UnrankKSubset[m_Integer, 1, s_List] := {s[[m + 1]]}
UnrankKSubset[0, k_Integer, s_List] := Take[s, k]
UnrankKSubset[m_Integer, k_Integer, s_List] :=
Block[{i = 1, n = Length[s], x1, u, $RecursionLimit = Infinity},
u = Binomial[n, k];
While[Binomial[i, k] < u - m, i++];
x1 = n - (i - 1);
Prepend[UnrankKSubset[m - u + Binomial[i, k], k-1, Drop[s, x1]], s[[x1]]]
]
用法如下:
UnrankKSubset[5, 3, {0, 1, 2, 3, 4}]
{0, 3, 4}
产生集合{0,1,2,3,4}的第6个(从0开始索引)长度为3的组合。
答案 1 :(得分:1)
这个问题有一个非常有效的算法,它也包含在最近发表的文章中:
Knuth,计算机程序设计的艺术,第4A卷(第7.2.1.3节)。 / p>
由于您不关心生成组合的顺序,因此我们使用组合的词典顺序,其中每个组合以降序顺序列出。因此,对于r = 3,3个符号的前11个组合将是:210,310,320,321,410,420,421,430,431,432,510。这种排序的优点是枚举独立于N;实际上它是对来自{0,1,2,...}的3个符号的所有组合的枚举。
有一种标准方法可以直接生成 i 组合给定i,以便测试符号s
是否是的一部分我是组合,你可以简单地生成并检查。
r符号的多少组合以特定符号s开头?好吧,其余的r-1位置必须来自s符号0,1,2,...,s-1,所以它是(s选择r-1),其中(s选择r-1)或C(s,r) -1)是二项式系数,表示从s对象中选择r-1个对象的方式的数量。对于所有s都是如此, i 组合的第一个符号是最小的s,这样
Σ k = 0 s (k选择r-1)≥i。
一旦你知道第一个符号,问题就会减少到找到(i - Σ k = 0 s-1 (k选择r-1)) - th r-1符号的组合,我们已经减去那些以小于s的符号开头的组合。
Python代码(您可以更有效地编写C(n,r)
,但这对我们来说足够快了):
#!/usr/bin/env python
tC = {}
def C(n,r):
if tC.has_key((n,r)): return tC[(n,r)]
if r>n-r: r=n-r
if r<0: return 0
if r==0: return 1
tC[(n,r)] = C(n-1,r) + C(n-1,r-1)
return tC[(n,r)]
def combination(r, k):
'''Finds the kth combination of r letters.'''
if r==0: return []
sum = 0
s = 0
while True:
if sum + C(s,r-1) < k:
sum += C(s,r-1)
s += 1
else:
return [s] + combination(r-1, k-sum)
def Func(N, r, i, s): return s in combination(r, i)
for i in range(1, 20): print combination(3, i)
print combination(500, 10000000000000000000000000000000000000000000000000000000000000000)
注意这是多快:它在不到0.5秒的时间内找到500字母的100000000000000000000000000000000000000000000000000000000000000000000th组合(以542开头)。
答案 2 :(得分:0)
我编写了一个类来处理使用二项式系数的常用函数,这是您的问题所处的问题类型。它执行以下任务:
以任意N选择K到文件的格式输出所有K索引。 K索引可以用更具描述性的字符串或字母代替。这种方法使解决这类问题变得非常简单。
将K索引转换为已排序二项系数表中条目的正确索引。这种技术比依赖迭代的旧发布技术快得多。它通过使用Pascal三角形中固有的数学属性来实现。我的论文谈到了这一点。我相信我是第一个发现和发布这种技术的人,但我可能错了。
将已排序的二项系数表中的索引转换为相应的K索引。
使用Mark Dominus方法计算二项式系数,这样就不太可能溢出并使用更大的数字。
该类是用.NET C#编写的,它提供了一种通过使用通用列表来管理与问题相关的对象(如果有)的方法。此类的构造函数采用名为InitTable的bool值,当为true时,将创建一个通用列表来保存要管理的对象。如果此值为false,则不会创建表。不需要创建表来执行上述4种方法。提供访问者方法来访问该表。
有一个关联的测试类,它显示了如何使用该类及其方法。它已经过2个案例的广泛测试,并且没有已知的错误。
要阅读此课程并下载代码,请参阅Tablizing The Binomial Coeffieicent。
此类可以轻松应用于您的问题。如果您具有二项式系数表的等级(或索引),则只需调用返回数组中K索引的类方法。然后,遍历返回的数组以查看是否有任何K-index值与您拥有的值匹配。很直接......