-
Notifications
You must be signed in to change notification settings - Fork 1
/
combi.c
110 lines (87 loc) · 1.95 KB
/
combi.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <assert.h>
#include <string.h>
#include "puzzles.h"
/* horrific and doesn't check overflow. */
static long factx(long x, long y)
{
long acc = 1, i;
for (i = y; i <= x; i++)
acc *= i;
return acc;
}
void reset_combi(combi_ctx *combi)
{
int i;
combi->nleft = combi->total;
for (i = 0; i < combi->r; i++)
combi->a[i] = i;
}
combi_ctx *new_combi(int r, int n)
{
long nfr, nrf;
combi_ctx *combi;
assert(r <= n);
assert(n >= 1);
combi = snew(combi_ctx);
memset(combi, 0, sizeof(combi_ctx));
combi->r = r;
combi->n = n;
combi->a = snewn(r, int);
memset(combi->a, 0, r * sizeof(int));
nfr = factx(n, r+1);
nrf = factx(n-r, 1);
combi->total = (int)(nfr / nrf);
reset_combi(combi);
return combi;
}
/* returns NULL when we're done otherwise returns input. */
combi_ctx *next_combi(combi_ctx *combi)
{
int i = combi->r - 1, j;
if (combi->nleft == combi->total)
goto done;
else if (combi->nleft <= 0)
return NULL;
while (combi->a[i] == combi->n - combi->r + i)
i--;
combi->a[i] += 1;
for (j = i+1; j < combi->r; j++)
combi->a[j] = combi->a[i] + j - i;
done:
combi->nleft--;
return combi;
}
void free_combi(combi_ctx *combi)
{
sfree(combi->a);
sfree(combi);
}
/* compile this with:
* gcc -o combi.exe -DSTANDALONE_COMBI_TEST combi.c malloc.c
*/
#ifdef STANDALONE_COMBI_TEST
#include <stdio.h>
void fatal(char *fmt, ...)
{
abort();
}
int main(int argc, char *argv[])
{
combi_ctx *c;
int i, r, n;
if (argc < 3) {
fprintf(stderr, "Usage: combi R N\n");
exit(1);
}
r = atoi(argv[1]); n = atoi(argv[2]);
c = new_combi(r, n);
printf("combi %d of %d, %d elements.\n", c->r, c->n, c->total);
while (next_combi(c)) {
for (i = 0; i < c->r; i++) {
printf("%d ", c->a[i]);
}
printf("\n");
}
free_combi(c);
}
#endif