确定一个符号是否是第 i 个组合 nCr 的一部分

发布于 2024-11-05 12:54:17 字数 1581 浏览 5 评论 0原文

更新: 组合学和取消排名最终是我所需要的。 下面的链接有很大帮助:

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) = True/False 或 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 矩阵的“角”,依此类推。

另一种关系
理想情况下,解决方案的形式应类似于以下答案: 根据位置计算组合

长度为 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

我需要类似的东西,但不允许重复。

感谢您到目前为止关注这个问题:]
凯文.

UPDATE:
Combinatorics and unranking was eventually what I needed.
The links below helped alot:

http://msdn.microsoft.com/en-us/library/aa289166(v=vs.71).aspx

http://www.codeproject.com/Articles/21335/Combinations-in-C-Part-2

The Problem
Given a list of N symbols say {0,1,2,3,4...}
And NCr combinations of these

eg. NC3 will generate:

0 1 2  
0 1 3  
0 1 4  
...  
...  
1 2 3  
1 2 4  
etc...  

For the ith combination (i = [1 .. NCr]) I want to determine Whether a symbol (s) is part of it.
Func(N, r, i, s) = True/False or 0/1
eg. Continuing from above
The 1st combination contains 0 1 2 but not 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  

Current approaches and tibits that might help or be related.
Relation to matrices
For r = 2 eg. 4C2 the combinations are the upper (or lower) half of a 2D matrix

    1,2 1,3 1,4  
    ----2,3 2,4  
    --------3,4  

For r = 3 its the corner of a 3D matrix or cube
for r = 4 Its the "corner" of a 4D matrix and so on.

Another relation
Ideally the solution would be of a form something like the answer to this:
Calculate Combination based on position

The nth combination in the list of combinations of length r (with repitition allowed), the ith symbol can be calculated
Using integer division and remainder:

n/r^i % r = (0 for 0th symbol, 1 for 1st symbol....etc)

eg for the 6th comb of 3 symbols the 0th 1st and 2nd symbols are:

i = 0 => 6 / 3^0 % 3 = 0   
i = 1 => 6 / 3^1 % 3 = 2   
i = 2 => 6 / 3^2 % 3 = 0   

The 6th comb would then be 0 2 0

I need something similar but with repition not allowed.

Thank you for following this question this far :]
Kevin.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

桃气十足 2024-11-12 12:54:17

我相信您的问题是取消排名组合或子集的问题。

我将在 Mathematica 中为您提供一个实现,来自包 Combinatorica,但是 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 的组合。

I believe your problem is that of unranking combinations or subsets.

I will give you an implementation in Mathematica, from the package Combinatorica, but the Google link above is probably a better place to start, unless you are familiar with the semantics.

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]]]
       ]

Usage is like:

UnrankKSubset[5, 3, {0, 1, 2, 3, 4}]
   {0, 3, 4}

Yielding the 6th (indexing from 0) length-3 combination of set {0, 1, 2, 3, 4}.

吲‖鸣 2024-11-12 12:54:17

对于这个问题有一个非常有效的算法,该算法也包含在最近出版的:
Knuth,计算机编程的艺术,第 4A 卷(第 7.2.1.3 节)中。

由于您不关心组合的生成顺序,因此我们使用组合的字典顺序,其中每个组合均按降序顺序列出。因此,对于 r=3,3 个符号的前 11 个组合将是:210、310、320、321、410、420、421、430、431、432、510。这种排序的优点是枚举独立于n;事实上,它是对 {0, 1, 2, …} 中 3 个符号的所有组合的枚举。

有一个标准方法可以直接生成给定i的第i个组合,因此可以测试符号s是否是的一部分第 i 个组合,您可以简单地生成它并检查。

方法

有多少种以特定符号 s 开头的 r 符号组合?好吧,剩下的 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=0s(k选择r-1)≥i。

一旦你知道了第一个符号,问题就简化为找到 r 的 (i - Σk=0s-1(k select r-1))-th 组合-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)

注意这有多快:它找到了第 100000000000000000000000000000000000000000000000000000000000000000 个 500 个字母的第 1000000000000000000 个组合(以542)不到 0.5 秒。

There's a very efficient algorithm for this problem, which is also contained in the recently published:
Knuth, The Art of Computer Programming, Volume 4A (section 7.2.1.3).

Since you don't care about the order in which the combinations are generated, let's use the lexicographic order of the combinations where each combination is listed in descending order. Thus for r=3, the first 11 combinations of 3 symbols would be: 210, 310, 320, 321, 410, 420, 421, 430, 431, 432, 510. The advantage of this ordering is that the enumeration is independent of n; indeed it is an enumeration over all combinations of 3 symbols from {0, 1, 2, …}.

There is a standard method to directly generate the ith combination given i, so to test whether a symbol s is part of the ith combination, you can simply generate it and check.

Method

How many combinations of r symbols start with a particular symbol s? Well, the remaining r-1 positions must come from the s symbols 0, 1, 2, …, s-1, so it's (s choose r-1), where (s choose r-1) or C(s,r-1) is the binomial coefficient denoting the number of ways of choosing r-1 objects from s objects. As this is true for all s, the first symbol of the ith combination is the smallest s such that

k=0s(k choose r-1) ≥ i.

Once you know the first symbol, the problem reduces to finding the (i - ∑k=0s-1(k choose r-1))-th combination of r-1 symbols, where we've subtracted those combinations that start with a symbol less than s.

Code

Python code (you can write C(n,r) more efficiently, but this is fast enough for us):

#!/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)

Note how fast this is: it finds the 10000000000000000000000000000000000000000000000000000000000000000th combination of 500 letters (it starts with 542) in less than 0.5 seconds.

思慕 2024-11-12 12:54:17

我编写了一个类来处理处理二项式系数的常用函数,这是您的问题所属的问题类型。它执行以下任务:

  1. 以良好的格式将任意 N 选择 K 的所有 K 索引输出到文件中。 K 索引可以替换为更具描述性的字符串或字母。这种方法使得解决此类问题变得非常简单。

  2. 将 K 索引转换为排序二项式系数表中条目的正确索引。该技术比依赖迭代的旧发布技术要快得多。它通过使用帕斯卡三角形固有的数学属性来实现这一点。我的论文谈到了这一点。我相信我是第一个发现并发布此技术的人,但我可能是错的。

  3. 将排序二项式系数表中的索引转换为相应的 K 索引。

  4. 使用Mark Dominus方法来计算二项式系数,这种方法不太可能溢出并适用于更大的数字。

  5. 该类是用 .NET C# 编写的,并提供了一种使用通用列表来管理与问题相关的对象(如果有)的方法。该类的构造函数采用一个名为 InitTable 的布尔值,当该值为 true 时,将创建一个通用列表来保存要管理的对象。如果该值为 false,则不会创建该表。执行上述 4 种方法不需要创建该表。提供了访问器方法来访问表。

  6. 有一个关联的测试类,它显示了如何使用该类及其方法。它已经通过 2 个案例进行了广泛的测试,没有已知的错误。

要了解此类并下载代码,请参阅制表二项式系数

此类可以轻松应用于您的问题。如果您有二项式系数表的排名(或索引),则只需调用返回数组中的 K 索引的类方法即可。然后,循环访问返回的数组以查看是否有任何 K 索引值与您拥有的值匹配。非常简单...

I have written a class to handle common functions for working with the binomial coefficient, which is the type of problem that your problem falls under. It performs the following tasks:

  1. Outputs all the K-indexes in a nice format for any N choose K to a file. The K-indexes can be substituted with more descriptive strings or letters. This method makes solving this type of problem quite trivial.

  2. Converts the K-indexes to the proper index of an entry in the sorted binomial coefficient table. This technique is much faster than older published techniques that rely on iteration. It does this by using a mathematical property inherent in Pascal's Triangle. My paper talks about this. I believe I am the first to discover and publish this technique, but I could be wrong.

  3. Converts the index in a sorted binomial coefficient table to the corresponding K-indexes.

  4. Uses Mark Dominus method to calculate the binomial coefficient, which is much less likely to overflow and works with larger numbers.

  5. The class is written in .NET C# and provides a way to manage the objects related to the problem (if any) by using a generic list. The constructor of this class takes a bool value called InitTable that when true will create a generic list to hold the objects to be managed. If this value is false, then it will not create the table. The table does not need to be created in order to perform the 4 above methods. Accessor methods are provided to access the table.

  6. There is an associated test class which shows how to use the class and its methods. It has been extensively tested with 2 cases and there are no known bugs.

To read about this class and download the code, see Tablizing The Binomial Coeffieicent.

This class can easily be applied to your problem. If you have the rank (or index) to the binomial coefficient table, then simply call the class method that returns the K-indexes in an array. Then, loop through that returned array to see if any of the K-index values match the value you have. Pretty straight forward...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文