【问题标题】:How can I get the index of a given combination?如何获取给定组合的索引?
【发布时间】:2020-05-12 16:55:16
【问题描述】:

我有一个数字数组,每个数组有 5 个元素,从 0 到 8,我必须订购而不是使用这种组合,我的意思是:

i=0, {0,0,0,0,0}
i=1, {0,0,0,0,1}
i=2, {0,0,0,0,2}
i=3, {0,0,0,0,3}
i=4, {0,0,0,0,4}
i=5, {0,0,0,0,5}
i=6, {0,0,0,0,6}
i=7, {0,0,0,0,7}
i=8, {0,0,0,0,8}
i=9, {0,0,0,1,1}
     ...
i=1285, {7,8,8,8,8}
i=1286, {8,8,8,8,8}

所以如果我将 {0,0,1,1,2} 赋予函数,它会返回 7。 我考虑过使用Combinatorial number system 但我错过了一些我不知道它是什么的东西,下面的代码不起作用

#include <stdio.h>
#include <stdlib.h>

#define size 1287

int combination[9][5] =     {
                    {0,  0,   0,      0,      0},
                    {1,  1,   1,      1,      1},
                    {2,  3,   4,      5,      6},
                    {3,  3,   6,     15,     21},
                    {4, 10,  20,     35,     56},
                    {5, 15,  35,     70,    126},
                    {6, 21,  56,    126,    252},
                    {7, 28,  84,    210,    462},
                    {8, 36, 120,    330,    792}
                };

int getKey(int array[]){
    int key=0;
    int tempArray[9] = {0};
    for(int i=0;i<5;i++){
        tempArray[array[i]]++;
    }
    int j=0;
    for(int i=0;i<9;i++){
        if(tempArray[i]!=0){
            while(tempArray[i]!=0){
                array[j++] = i;
                key += combination[i][5-j];
                tempArray[i]--;
            }
        }
    }
    return key;
}

int main(){
  int it[5];
  for(it[0]  = 0 ;it[0]<9;it[0]++){
    for(it[1]=it[0];it[1]<9;it[1]++){
      for(it[2]=it[1];it[2]<9;it[2]++){
        for(it[3]=it[2];it[3]<9;it[3]++){
          for(it[4]=it[3];it[4]<9;it[4]++){
            printf("{%d %d %d %d %d} = %d\n",it[0],it[1],it[2],it[3],it[4],getKey(it));
          }
        }
      }
    }
  }
  return 0;
}

Obs:我使用计数排序来保持字典顺序,理论上我会收到未排序的数组。

【问题讨论】:

    标签: c math combinations combinatorics binomial-coefficients


    【解决方案1】:

    我会给你我为你昨天发布并删除的这个问题的先前版本写的答案。 (顺便说一句,这是一种糟糕的形式。)

    我们称二项式系数为 C(n, k) = n!/(k!(n-k)!)

    从 s 个符号的字母表中抽取的 m 个字母的无序串的数量为 C(m+s-1, s-1)。我们称其为 D(m, s)。在这种情况下,D(5, 9) = C(5+9-1, 9-1) = C(13, 8) = 1287

    让我们对每个字符串进行排序,然后给它们编号:

    aaaaa 1
    aaaab 2
    aaaac 3
    ...
    aaaai 9
    aaabb 10
    aaabc 11
    ...
    

    如果一个字符串包含 5 个 a,那么它的个数是 D(5, 1) = C(5+1-1, 1-1) = C(5, 0) = 1。
    如果一个字符串包含 4 个 a,它的数字是 1 加上一个由非 a 字母确定的数字,它上升到 D(1,8) = C(1+8-1,8-1) = C(8, 7) = 8。所以它们上升到 1+8=9。
    如果一个字符串包含 3 个 a,它的数字是 9 加上一个由非 a 字母确定的数字,它上升到 D(2,8) = C(9,7) = 36,所以 9+36=45。 如果一个字符串包含 2 个 a,那么它的数量在 [46,165] 中。
    如果一个字符串包含 1 个 a,那么它的编号在 [166, 495] 中。
    如果字符串不包含 a,则其编号在 [496, 1287] 中。

    那么字符串“aabgg”呢?它的数字是(45)+(8)+(7)+(6)+(5)+(4)+(1)=76

    没有碰撞,索引的计算是O(sm(s+m)),对于m=5和s=9来说还不算太差。

    编辑:澄清一下,让我们定义一下

    E(j, m, s) = D(0,s-1)+D(1,s-1)+...+D(m-j-1,s-1)
    

    假设从 s 个符号的字母表中提取的 m 个字母组成的字符串包含字母表的第一个字母中的 j 个。在目录中在第一个这样的字符串之前有 E(j,m,s) 个字符串。 例如,在第一个正好以两个 a 开头的字符串(“aabbb”)之前,有 E( 2, 5, 9)=45 个字符串。

    要找到“aabbb”,我们必须数出 45 个字符串。
    要从 "aabbb" 到下一个恰好包含一个 b ("aabcc") 的字符串,我们必须计算出 E(1, 3, 8) = 8 个字符串。
    从那里到下一个不包含 c ("aabdd") 的字符串,E(0, 2, 7) = 7 个字符串。
    No d ("aabee"): E(0, 2, 6) = 6
    没有 e ("aabff"): E(0, 2, 5) = 5
    没有 f ("aabgg"): E(0, 2, 4) = 4
    我们必须计算“aabgg”本身:1

    【讨论】:

    • 真的很抱歉,我把这个问题给我的一个朋友看,他说英文有很多错误,最好重写,所以我趁机写了一个更简单的方法
    • 示例中的“(8)+(7)+(6)+(5)+(4)+(1)”是从哪里来的?
    • E(2,5,9) = 45 怎么算?如果 E(2,5,9) = D(3,8)+D(4,8)+D(5,8) = C(10,7)+C(11,7)+C(12,7 ) = 120+330+792 = 1242
    • @NedLandy:对不起,我把代数抄错了。我会编辑。
    【解决方案2】:

    嗯,我认为这看起来像 oct number 1...8

    0 = {00000}
    1 = {00001}
    2 = {00002}
    8 = {00010}
    

    如果这就是你的意思

    我认为这个算法是最好的

       int get_key(int a[5]){
          int idx, rval=0;
          for(i=4; i<=0; i--)
             rval += powl(a[i], i);
          return rval; 
       }
    
    

    【讨论】:

    • 这种情况下的问题是 {0 0 0 0 1} = {0 0 0 1 0},八进制数没有发生什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-24
    • 1970-01-01
    相关资源
    最近更新 更多