void listcomb_from_index(int *array, int n, int k, int index) { int ret = 0; int i, j, nck; /* nck equals n choose k; we adjust it gradually as we alter n and k. */ nck = comb_count(n, k); j = 0; while (k > 0) { /* * The element here is j in the first (n-1 choose k-1) * positions, otherwise more than j. * * FIXME: it would be nice if we could find a closed form * for this and replace the while loop with some sort of * binary search, thus rendering the algorithm O(k) rather * than O(n). May not be possible, but worth thinking * about. */ while (index >= nck * k / n) { index -= nck * k / n; nck = nck * (n-k) / n; n--; j++; } nck = nck * k / n; k--; *array++ = j++; n--; } }
void setcomb_from_index(char *array, int n, int k, int index) { int i, nck; /* nck equals n choose k; we adjust it gradually as we alter n and k. */ nck = comb_count(n, k); while (k > 0) { if (index < nck * k / n) { /* * First element is here. */ *array = 1; nck = nck * k / n; k--; } else { /* * It isn't. */ *array = 0; index -= nck * k / n; nck = nck * (n-k) / n; } array++; n--; } /* * Fill up the remainder of the array with zeroes. */ while (n-- > 0) *array++ = 0; }
int setcomb_to_index(char *array, int n, int k) { int ret = 0; int i, nck; /* nck equals n choose k; we adjust it gradually as we alter n and k. */ nck = comb_count(n, k); while (1) { if (k == 0) return ret; /* only one position now */ if (*array) { /* * First element found. */ nck = nck * k / n; k--; } else { /* * First element not found, meaning we have just * skipped over (n-1 choose k-1) positions. */ ret += nck * k / n; nck = nck * (n-k) / n; } array++; n--; } }
void comb(int list[],int list_size, int start, int count) { int i; if (count == list_size-1) { for(i=0; i<3; i++){ printf("%c",list[i]); } } for (i=start; i<list_size; i++) { comb_count (list, list_size, start, i); } }
int listcomb_to_index(int *array, int n, int k) { int ret = 0; int i, j, nck; /* nck equals n choose k; we adjust it gradually as we alter n and k. */ nck = comb_count(n, k); j = 0; while (k > 0) { /* * If the element here is not j, we must skip over (n-1 * choose k-1) positions in which it is. * * FIXME: it would be nice if we could find a closed form * for this and replace the while loop with some sort of * binary search, thus rendering the algorithm O(k) rather * than O(n). May not be possible, but worth thinking * about. */ while (j++ < *array) { ret += nck * k / n; nck = nck * (n-k) / n; n--; } /* * Now we've found an element, so decrement both n and k. */ nck = nck * k / n; k--; array++; n--; } return ret; }
void test_setcomb(int n) { char a1[COMB_NMAX], a2[COMB_NMAX]; int indices[COMB_NMAX+1]; int i, j, k, index; #ifndef QUIET printf("setcomb round-trip index tests, n=%d\n", n); #endif /* * Enumerate all 2^n possible subsets of {0,...,n-1}, and check * that setcomb_to_index() translates each one correctly to a * combination index, that setcomb_from_index() translates each * one correctly back again, and that the indices are in the * expected order. */ for (i = 0; i <= n; i++) indices[i] = comb_count(n, i) - 1; for (i = 0; i < (1 << n); i++) { k = 0; for (j = 0; j < n; j++) { a1[j] = (i & (1 << (n-1-j))) != 0; k += a1[j] != 0; } index = setcomb_to_index(a1, n, k); setcomb_from_index(a2, n, k, index); #ifndef QUIET for (j = 0; j < n; j++) putchar(a1[j] ? '#' : '-'); printf(" (k =%3d) ->%5d -> ", k, index); for (j = 0; j < n; j++) putchar(a2[j] ? '#' : '-'); putchar('\n'); #endif EQ(index, indices[k]); indices[k]--; EQ(memcmp(a1, a2, n), 0); } /* * Now enumerate using setcomb_first() and setcomb_next(), and * verify that we get the expected number of combinations, that * each combination is valid, and that the indices are also as * expected. */ for (k = 0; k <= n; k++) { index = 0; #ifndef QUIET printf("setcomb enumeration tests, n=%d, k=%d\n", n, k); #endif setcomb_first(a1, n, k); do { for (i = j = 0; j < n; j++) i += a1[j] != 0; EQ(i, k); i = setcomb_to_index(a1, n, k); #ifndef QUIET for (j = 0; j < n; j++) putchar(a1[j] ? '#' : '-'); printf(" ->%5d\n", i); #endif EQ(index, i); index++; } while (setcomb_next(a1, n, k)); i = comb_count(n, k); EQ(index, i); } }