Search code examples
cmathcombinationscombinatoricsbinomial-coefficients

How can I get the index of a given combination?


I have a sequence of arrays of numbers with 5 elements each, from 0 to 8, and I have to order than using that combination, I mean:

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}

so if I give {0,0,1,1,2} to the function it's returns 7. I thought about using the Combinatorial number system but I'm missing something that I don't know what it is, the code below just doesn't work

#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: I'm using counting sort to keep the lexicographic order, in theory I will receive unsorted arrays.


Solution

  • I will give you the Answer I wrote for the previous version of this question which you posted yesterday and deleted. (And that's bad form, by the way.)

    Let's call the binomial coefficient C(n, k) = n!/(k!(n-k)!)

    The number of unordered strings of m letters drawn from an alphabet of s symbols is C(m+s-1, s-1). Let's call that D(m, s). In this case, D(5, 9) = C(5+9-1, 9-1) = C(13, 8) = 1287

    Let's sort each string, then number them:

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

    If a string contains 5 a's, its number is D(5, 1) = C(5+1-1, 1-1) = C(5, 0) = 1.
    If a string contains 4 a's, its number is 1 plus a number determined by the non-a letter, which goes up to D(1,8) = C(1+8-1,8-1) = C(8, 7) = 8. So they go up to 1+8=9.
    If a string contains 3 a's, its number is 9 plus a number determined by the non-a letters, which goes up to D(2,8) = C(9,7) = 36, so 9+36=45.
    If a string contains 2 a's, its number is in [46,165].
    If a string contains 1 a, its number is in [166, 495].
    If a string contains no a, its number is in [496, 1287].

    So how about the string "aabgg"? It's number is (45)+(8)+(7)+(6)+(5)+(4)+(1)=76

    No collisions, and the calculation of the index is O(sm(s+m)), which is not too bad for m=5 and s=9.

    EDIT: to clarify, let's define

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

    Suppose a string of m letters drawn from an alphabet of s symbols contains j of the first letter of the alphabet. There are E(j,m,s) strings in the catalogue before the first such string. For instance, before the first string that begins with exactly two a's ("aabbb"), there are E(2, 5, 9)=45 strings.

    To get to "aabbb" we must count out 45 strings.
    To get from "aabbb" to the next string that contains exactly one b ("aabcc"), we must count out E(1, 3, 8) = 8 strings.
    From there to the next string that contains no c ("aabdd"), E(0, 2, 7) = 7 strings.
    No d ("aabee"): E(0, 2, 6) = 6
    No e ("aabff"): E(0, 2, 5) = 5
    No f ("aabgg"): E(0, 2, 4) = 4
    And we must count "aabgg" itself: 1