|
[ 簡単な説明 ]
組合せ生成ルーチンを紹介します。 組合せは、配列 int p[ ] に1〜nの数値で格納されます。 各組合せの生成毎に showcomb ルーチンを呼び出すので、実際の応用においては、ここ(showcomb ルーチン)に各組合せを使用した処理を書きます。 |
/* comb.c 組合せ(nCk)の生成 generation of combination */
#include <stdio.h>
#include <math.h>
#define set unsigned int
set K, N, x, overx;
extern void showcomb(int p[], int n, int k); /* このルーチンで各組合せに対する処理を行う */
void gencomb(int p[], int n, int k); /* 組合せ生成マスタールーチン */
void gencomb1(int p[], int n, int k); /* 高速組合せ生成ルーチン(但し、n < 16) */
void gencomb2(int p[], int n, int k); /* 組合せ生成ルーチン(n > 15 で使用) */
int subcomb(int p[]); /* gencomb1() のスレーブルーチン */
set nextset(void); /* gencomb1() のスレーブルーチン */
void gencomb(int p[], int n, int k)
{
int i;
if(n < k || k <= 0)
{
fprintf(stderr, "Error : illegal parameter input in gencomb().\n");
return;
}
if(k == 0)
{
p[0] = -1;
fprintf(stderr, "Warning : nCk (k=0). No combination select.\n");
return;
}
if(n < 16) gencomb1(p, n, k);
else gencomb2(p, n, k);
return;
}
void gencomb1(int p[], int n, int k)
{
int j, *q;
set s;
N = n;
K = k;
x = (1 << K) - 1L;
overx = ~((1 << N) - 1L);
for(j = 1, q = p, s = x; j <= N; j++)
{
if(s & 1) *q++ = j;
s >>= 1;
}
while(subcomb(p)) showcomb(p, n, k);
}
int subcomb(int p[])
{
int j, *q;
set s;
x = nextset();
if(x & overx) return 0;
for(j = 1, q = p, s = x; j <= N; j++)
{
if(s & 1) *q++ = j;
s >>= 1;
}
return 1;
}
set nextset(void)
{
set smallest, ripple, new_smallest, ones;
smallest = x & -x;
ripple = x + smallest;
new_smallest = ripple & -ripple;
ones = ((new_smallest / smallest) >> 1) - 1;
return ripple | ones;
}
void gencomb2(int p[], int n, int k)
{
int flag, i, j, nk;
for(i = 0; i < k; i++) p[i] = i;
do
{
showcomb(p, n, k);
flag = 0;
for(i = k - 1, nk = n - 1; i >= 0; i--, nk--)
{
if(p[i] < nk)
{
flag = 1;
p[i]++;
for(j = i + 1; j < k; j++) p[j] = p[j - 1] + 1;
break;
}
}
} while(flag);
}
|