【问题标题】:Determine whether a symbol is part of the ith combination nCr确定符号是否是第 i 个组合 nCr 的一部分
【发布时间】:2011-08-18 05:42:05
【问题描述】:

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

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 or 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 组合是二维矩阵的上半部分(或下半部分)

    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

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

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

【问题讨论】:

  • 或许添加homework标签
  • @Amit 你为什么认为这是家庭作业?
  • 问题交叉发布在math.SE。 (所以我在这里交叉发布了我的答案。:p 有更多代码,没有 TeX 标记。)
  • 更新:组合学和未排序最终是我所需要的。下面的链接帮助很大:link1link2
  • 感谢您的接受。我很高兴它有帮助。

标签: algorithm function combinations combinatorics


【解决方案1】:

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

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

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

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

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

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

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

要了解该课程并下载代码,请参阅Tablizing The Binomial Coeffieicent

这个类可以很容易地应用于你的问题。如果您有二项式系数表的等级(或索引),则只需调用返回数组中 K 索引的类方法。然后,遍历返回的数组以查看是否有任何 K-index 值与您的值匹配。很直接...

【讨论】:

    【解决方案2】:

    对于这个问题有一个非常有效的算法,它也包含在最近出版的:
    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是否是ith 组合,您可以简单地生成它并检查。

    方法

    有多少 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=0s(k 选择 r-1) ≥ i。

    一旦你知道了第一个符号,问题就简化为找到 (i - ∑k=0s-1(k choose r-1))-第 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 秒的时间内找到 1000000000000000000000000000000000000000000000000000 个 500 个字母(以 542 开头)的组合。

    【讨论】:

      【解决方案3】:

      我相信您的问题是unranking combinations 或子集的问题。

      我会给你一个 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 开始索引)length-3 组合。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-21
        • 2010-10-12
        • 1970-01-01
        • 1970-01-01
        • 2013-05-27
        • 2021-07-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多