横丁の名探偵

トップ > Cマガ電脳クラブ挑戦記録の部屋(過去) > Cマガ電脳クラブソースリスト(2002年分)



第141回(12月)クロ交換シロ

/******************************************************************************
Cマガジン2002年9月出題 電脳クラブ(クロ交換シロ)
*****************************************************************************/*
#include <stdio.h>
#include <stdlib.h>
#define OFF 0 /* オフ /*
#define ON 1  /* オン /*
#define NON 0 /* 何も置いてない /*
#define BLACK 1 /* 黒 /*
#define WHITE 2 /* 白 /*
#define ORG 0 /* 原点 /*
#define NOTUSED -1 /* 未使用 /*
#define SHOKI -1 /* 1手目における前回手 /*
#define N1 1 /* 最小単位 /*
#define N3 3 /* 状態(なし、黒、白)の数 /*
#define N6 6 /* コマの数 /*
#define NM 4 /* 移動可能な個所の最大数 /*
#define W1(y , x) (y) * sizeX + (x) /* work用データ取得 /*
#define M1(a , b) a * NM + b /* move用データ取得 /*
int nb = ORG; /* 盤上でコマを置ける個所の数 /*
int np = N1; /* 盤のパターンの数 /*
int *min = NULL; /* その盤のパターンにたどり着いた最小手数 /*
int *ban = NULL; /* 盤 /*
int endId; /* 終了ID /*
int *move = NULL; /* 移動先 /*
int *nMove = NULL; /* 移動先の数 /*
int fFind = OFF;
/******************************************************************************
機能:終了処理(確保したメモリの開放)
引数:なし
戻り値:なし
*****************************************************************************/*
void end(void)
{
    free(min);
    free(ban);
    free(nMove);
    free(move);
}
#define B 'B' /* 黒コマ /*
#define W 'W' /* 白コマ /*
#define STAR '*' /* 盤の外 /*
/******************************************************************************
機能:IDを求める。
引数:パターン
戻り値:ID
*****************************************************************************/*
int getId(int pat[])
{
    int id = ORG; /* ID /*
    int i; /* ループの制御変数 /*
    for(i = ORG ; i < nb ; i++) id = id * N3 + pat[i];
    return(id);
}
/******************************************************************************
機能:初期化
引数:なし
戻り値:なし
*****************************************************************************/*
void init(void)
{
    static char *banDef[] = { /* 盤初期状態の定義 /*
        "** *" ,
        "**B*" ,
        "**B*" ,
        " WB " ,
        "*W**" ,
        "*W**" ,
        "* **" };
    int *work; /* 移動先データ取得用ワーク /*
    int x , y;
    int sizeX , sizeY; /* 盤の大きさ /*
    int n;
    int *endP; /* 終了パターン /*
    int i; /* ループの制御変数 /*
    sizeX = strlen(banDef[ORG]);
    sizeY = sizeof(banDef) / sizeof(banDef[ORG]);
    work = (int *)malloc(sizeof(int) * sizeX * sizeY);
    if(work == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        end();
        exit(EXIT_FAILURE);
    }
    for(y = ORG ; y < sizeY ; y++) {
        for(x = ORG ; x < sizeX ; x++) {
            work[W1(y , x)] = NOTUSED;
            if(*(banDef[y] + x) == STAR) continue;
            ban = (int *)realloc(ban , sizeof(int) * (nb + N1));
            if(ban == NULL) {
                fprintf(stderr , "realloc error at %d\n" , __LINE__);
                end();
                exit(EXIT_FAILURE);
            }
            if     (*(banDef[y] + x) == B) ban[nb] = BLACK;
            else if(*(banDef[y] + x) == W) ban[nb] = WHITE;
            else                       ban[nb] = NON;
            work[W1(y , x)] = nb;
            nb++;
            np *= N3;
        }
    }
    nMove = (int *)malloc(sizeof(int) * nb);
    if(nMove == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        end();
        exit(EXIT_FAILURE);
    }
    move =(int *)malloc(sizeof(int *) * nb * NM);
    if(move == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        end();
        exit(EXIT_FAILURE);
    }
    for(y = ORG ; y < sizeY ; y++) {
        for(x = ORG ; x < sizeX ; x++) {
            if(work[W1(y , x)] == NOTUSED) continue;
            n = ORG;
            if(x > ORG) { /* ← /*
                if(work[W1(y , x - N1)] != NOTUSED) {
                    move[M1(work[W1(y , x)] , n++)] = work[W1(y , x - N1)];
                }
            }
            if(x < sizeX - N1) { /* → /*
                if(work[W1(y , x  + N1)] != NOTUSED) {
                    move[M1(work[W1(y , x)] , n++)] = work[W1(y , x + N1)];
                }
            }
            if(y > ORG) { /* ↑ /*
                if(work[W1(y - N1 , x)] != NOTUSED) {
                    move[M1(work[W1(y , x)] , n++)] = work[W1(y - N1 ,x)];
                }
            }
            if(y < sizeY - N1) { /* ↓ /*
                if(work[W1(y + N1 , x)] != NOTUSED) {
                    move[M1(work[W1(y , x)] , n++)] = work[W1(y + N1 , x)];
                }
            }
            nMove[work[W1(y , x)]] = n;
        }
    }
    free(work);
    min = (int *)malloc(sizeof(int) * np);
    if(min == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        end();
        exit(EXIT_FAILURE);
    }
    endP = (int *)malloc(sizeof(int) * nb);
    if(endP == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        end();
        exit(EXIT_FAILURE);
    }
    for(i = ORG ; i < nb ; i++) { /* 終了パターンを求める /*
        if     (ban[i] == NON)   endP[i] = NON;
        else if(ban[i] == BLACK) endP[i] = WHITE;
        else                     endP[i] = BLACK;
    }
    endId = getId(endP); /* 終了IDを求める /*
    free(endP);
}
/******************************************************************************
機能:再帰呼び出し関数
引数:
  n   (I) ここまでの手数
  pos (I) 前回動いたコマの移動先
戻り値:なし
*****************************************************************************/*
void sub(int n , int pos)
{
    int i , j; /* ループの制御変数 /*
    int n1; /* n + 1 /*
    int id; /* ID /*
    id = getId(ban); /* 現IDを求める /*
    if(min[id] <= n) return; /* 過去に、より少ない手数で来ている /*
    min[id] = n; /* 手数を登録 /*
    if(id == endId) {  /* 終了ID /*
        fFind=ON;
        return;
    }
    n1 = n + N1;
    for(i = ORG ; i < nb ; i++) {
        if(ban[i] == NON) continue; /* そこにコマがない /*
        for(j = ORG ; j < nMove[i] ; j++) {
            if(ban[move[M1(i , j)]] != NON) continue; /* 移動先にコマがあった /*
            ban[move[M1(i , j)]] = ban[i]; /* 移動先 /*
            ban[i] = NON; /* 移動元 /*
            if(i == pos) sub(n  , move[M1(i , j)]); /* 前回と同じ手 /*
            else         sub(n1 , move[M1(i , j)]); /* 前回と異なる手 /*
            ban[i] = ban[move[M1(i , j)]]; /* 移動元に戻す /*
            ban[move[M1(i , j)]] = NON; /* 移動先をクリア /*
        }
    }
}
/******************************************************************************
機能:メイン
引数:なし
戻り値:0
*****************************************************************************/*
int main(void)
{
    int limit = N6; /* 探査する最大手数 /*
    int i; /* ループの制御変数 /*
    init();
    while(fFind == OFF) {
        limit++;
        for(i = ORG ; i < np ; i++) min[i] = limit; /* 最小手数を初期化 /*
        sub(ORG , SHOKI);
    }
    printf("解答:%d手\n" , min[endId]); /* 解答表示 /*
    end();
    return(EXIT_SUCCESS);
}



第140回(11月)整数解の怪

/******************************************************************************
Cマガジン電脳クラブ2002年8月出題(整数解の怪)
*****************************************************************************/*
#include <stdio.h>
#include <math.h>
int main(void)
{
    int m = 2 , n;
    int xt , yt , u , v;
    int x , y;
    int m2 , n2; /* m2 = m^2 , n2 = n^2 /* 
    double v2; /* v2 = v^2 /*
    while(1) {
        m2 = m * m;
        for(n = 1 ; n < m ; n++) {
            n2 = n * n;
            xt = 2 * m * n;
            yt = m2 - n2;
            u = m2 + n2;
            v2 = (double)u * (double)u - (double)xt * (double)yt;
            v = (int)sqrt(v2);
            if((double)v * (double)v != v2) continue;
                /* v2が平方数でなければ次へ /*
            x = xt < yt ? xt : yt; /* xt,ytの内、小さい方をxとする /*
            y = xt < yt ? yt : xt; /* xt,ytの内、大きい方をyとする /*
            if(x * 15 == y * 8) continue; /* x=8k && y=15k は除外する /*
            printf("x=%d y=%d u=%d v=%d\n" , x , y, u , v); /* 解答表示 /*
            return(0); /* 終了 /*
        }
        m++;
    }
}


第139回(10月)RUSH HOUR

/******************************************************************************
Cマガジン2002年7月号 電脳クラブ
*****************************************************************************/*
#include <stdio.h>
#include <stdlib.h>
#define OFF 0 /* オフ /*
#define ON  1 /* オン /*
#define BX 6 /* 駐車場の横方向の長さ /*
#define BX1 7 /* BX + 1 /*
#define BY 6 /* 駐車場の縦方向の長さ /*
#define BY1 7 /* BY + 1 /*
#define N24 24 /* 遷移の最大値 /*
#define NYOKO 6 /* 横方向の車の数 /*
#define NYOKO1 5 /* NYOKO - 1 /*
#define NTATE 7 /* 縦方向の車の数 /*
#define NTATE1 6 /* NTATE - 1 /*
#define NX 5 /* 車Xの番号 /*
#define NB 2 /* 2分岐の2 /*
#define N4 4 /* 車Xが外に出られる時のX座標 /*
#define N1 1 /* 最小単位 /*
#define N2 2 /* 0オリジンで3番目 /*
#define N3 3 /* 車の長さの最大値 /*
#define N0 0 /* 原点 /*
typedef struct {
    int x; /* 車の始点のX座標 /*
    int y; /* 車の始点のY座標 /*
    int len; /* 車の長さ /*
    char name; /* 車の名前 /*
} CARR;
CARR ax[] = { 1,0,2,'A' , 4,4,2,'G' , 0,5,2,'H' , 3,5,2,'I' ,
    0,3,3,'L' , 3,2,2,'X'};/* 横方向の車の定義 /*
CARR ay[] = { 4,0,2,'B' , 1,1,2,'C' , 2,1,2,'D' , 3,3,2,'E' ,
    2,4,2,'F' , 0,0,3,'J' , 5,1,3,'K'}; /* 縦方向の車の定義 /*
int b1[BY][BX]; /* 駐車場 /*
int nPat = N0; /* パターンの数 /*
typedef struct {
    int id; /* パターンのID /*
    int next[N24]; /* 次のパターン /*
    int nNext; /* 次のパターンの数 /*
    int rec; /* そのパターンにたどり着いた手数 /*
    int fEnd; /* 終了フラグ /*
} PAT;
PAT *pat;
typedef struct {
    int x[NYOKO]; /* 横方向の車の始点の移動中X座標 /*
    int y[NTATE]; /* 縦方向の車の始点の移動中Y座標 /*
} T1;
T1 t1;
int min; /* 最小手数 /*
/******************************************************************************
機能:パターン表示
引数:
  id (I) : パターンのID
戻り値:なし
*****************************************************************************/*
void dispZ(int id)
{
    int x , y;
    int i , j; /* ループの制御変数 /*
    for(y = N0 ; y < BY ; y++) { /* 描画する駐車場をクリア /*
        for(x = N0 ; x < BX ; x++) b1[y][x] = ' ';
    }
    for(i = NTATE1 ; i >= N0 ; i--) {
        y = id % (BY1 - ay[i].len); /* 縦方向の車の始点Y座標を求める /*
        for(j = N0 ; j < ay[i].len ; j++) b1[y + j][ay[i].x] = ay[i].name;
        id /= (BY1 - ay[i].len);
    }
    for(i = NYOKO1 ; i >= N0 ; i--) {
        x = id % (BX1 - ax[i].len); /* 横方向の車の始点X座標を求める /*
        for(j = N0 ; j < ax[i].len ; j++) b1[ax[i].y][x + j] = ax[i].name;
        id /= (BX1 - ax[i].len);
    }
    for(y = N0 ; y < BY ; y++) { /* 表示 /*
        for(x = N0 ; x < BX ; x++) printf("%c" , b1[y][x]);
        printf("\n");
    }
}
/******************************************************************************
機能:各車の始点座標からIDを求める
引数:
  t1 (i) 各車の座標
戻り値:ID
*****************************************************************************/*
int getId(T1 t1)
{
    int id = N0;
    int i; /* ループの制御変数 /*
    for(i = N0 ; i < NYOKO ; i++) /* 横方向 /*
        id = id * (BX1 - ax[i].len) + t1.x[i];
    for(i = N0 ; i < NTATE ; i++) /* 縦方向 /*
        id = id * (BY1 - ay[i].len) + t1.y[i];
    return(id);
}
/******************************************************************************
機能:IDから添え字番号を二分岐探査で求める。
引数:
  ID (I) : ID
戻り値:添え字番号
*****************************************************************************/*
int search(int id)
{
    int ps , pe , pm;
    ps = N0;
    pe = nPat - N1;
    while(pe - ps > N1) {
        pm = (ps + pe) / NB;
        if(pat[pm].id < id) ps = pm;
        else if(pat[pm].id == id) return(pm);
        else pe = pm;
    }
    if(pat[ps].id == id) return(ps);
    if(pat[pe].id == id) return(pe);
    printf("program error\n");
    exit(1);
}
int mode = OFF; /* OFF:パターンの数だけ求める ON:遷移を求める /*
/******************************************************************************
機能:縦方向の車を動かす。
引数:
  n (I) : 縦方向の車の順番
戻り値:なし
*****************************************************************************/*
void tateMove(int n)
{
    int y;
    int i , j , k; /* ループの制御変数 /*
    for(y = N0 ; y < BY1 - ay[n].len ; y++) {
        if(b1[y][ay[n].x] == ON) continue; /* 他の車がいる /*
        if(b1[y + 1][ay[n].x] == ON) continue; /* 他の車がいる /*
        if(ay[n].len == N3) { /* 他の車がいる /*
            if(b1[y + N2][ay[n].x] == ON) continue;
        }
        for(i = N0 ; i < ay[n].len ; i++) b1[y + i][ay[n].x] = ON;
        t1.y[n] = y;
        if(n == NTATE1) { /* 全部動かし終わったら /*
            if(mode == ON) { /* 遷移を求める場合 /*
                pat[nPat].id = getId(t1);
                pat[nPat].nNext = N0;
                for(j = N0 ; j < NYOKO ; j++) {
                    for(k = N0 ; k < ax[j].len ; k++)
                        b1[ax[j].y][t1.x[j] + k] = OFF;
                    k = N1; /* 横方向の車を負の方向に動かす /*
                    while(ON) {
                        if(t1.x[j] - k < N0) break;
                        if(b1[ax[j].y][t1.x[j] - k] == ON) break;
                        t1.x[j] -= k;
                        pat[nPat].next[pat[nPat].nNext] = getId(t1);
                        pat[nPat].nNext++;
                        t1.x[j] += k;
                        k++;
                    }
                    k = N1; /* 横方向の車を正の方向に動かす /*
                    while(ON) {
                        if(t1.x[j] + k + ax[j].len > BX) break;
                        if(b1[ax[j].y][t1.x[j] + k + ax[j].len - N1] == ON)
                            break;
                        t1.x[j] += k;
                        pat[nPat].next[pat[nPat].nNext] = getId(t1);
                        pat[nPat].nNext++;
                        t1.x[j] -= k;
                        k++;
                    }
                    for(k = N0 ; k < ax[j].len ; k++)
                        b1[ax[j].y][t1.x[j] + k] = ON;
                }
                for(j = N0 ; j < NTATE ; j++) {
                    for(k = N0 ; k < ay[j].len ; k++)
                        b1[t1.y[j] + k][ay[j].x] = OFF;
                    k = N1; /* 縦方向の車を負の方向に動かす /*
                    while(ON) {
                        if(t1.y[j] - k < N0) break;
                        if(b1[t1.y[j] - k][ay[j].x] == ON) break;
                        t1.y[j] -= k;
                        pat[nPat].next[pat[nPat].nNext] = getId(t1);
                        pat[nPat].nNext++;
                        t1.y[j] += k;
                        k++;
                    }
                    k = N1; /* 縦方向の車を正の方向に動かす /*
                    while(ON) {
                        if(t1.y[j] + k + ay[j].len > BY) break;
                        if(b1[t1.y[j] + k + ay[j].len - N1][ay[j].x] == ON)
                            break;
                        t1.y[j] += k;
                        pat[nPat].next[pat[nPat].nNext] = getId(t1);
                        pat[nPat].nNext++;
                        t1.y[j] -= k;
                        k++;
                    }
                    for(k = N0 ; k < ay[j].len ; k++)
                        b1[t1.y[j] + k][ay[j].x] = ON;
                }
                if(t1.x[NX] == N4) pat[nPat].fEnd = ON;
                else pat[nPat].fEnd = OFF;
            }
            nPat++;
        }
        else tateMove(n + N1);
        for(i = N0 ; i < ay[n].len ; i++) b1[y + i][ay[n].x] = OFF;
    }
}
/******************************************************************************
機能:横方向の車を動かす。
引数:
 n (I) : 横方向の車の順番
戻り値:なし
*****************************************************************************/*
void yokoMove(int n)
{
    int x , y;
    int i; /* ループの制御変数 /*
    y = ax[n].y;
    for(x = N0 ; x < BX1 - ax[n].len ; x++) {
        if(b1[ax[n].y][x] == ON) continue; /* 他の車がいる /*
        if(b1[ax[n].y][x + N1] == ON) continue; /* 他の車がいる /*
        if(ax[n].len == N3) { /* 他の車がいる /*
            if(b1[ax[n].y][x + N2] == ON) continue;
        }
        for(i = N0 ; i < ax[n].len ; i++) b1[ax[n].y][x + i] = ON;
        t1.x[n] = x;
        if(n == NYOKO1) tateMove(N0);      /* 横方向が終わったら縦方向 /*
        else            yokoMove(n + N1); /* 次の横方向の車 /*
        for(i = N0 ; i < ax[n].len ; i++) b1[ax[n].y][x + i] = OFF;
    }
}
int *hId1; /* ここまで辿ってきたID /*
int *hId2; /* 最小手数で辿ってきたID /*
/******************************************************************************
機能:解を求める再帰ルーチン
引数:
  n    (I) : パターンの添え字番号
  tesu (I) : ここまでの手数
戻り値:なし
*****************************************************************************/*
void subM(int n , int tesu)
{
    int i; /* ループの制御変数 /*
    if(tesu >= pat[n].rec) return;
    pat[n].rec = tesu;
    hId1[tesu] = n;
    if(pat[n].fEnd == ON) {
        if(tesu < min) {
            min = tesu;
            for(i = N0 ; i < tesu + N1 ; i++) hId2[i] = hId1[i];
        }
        return;
    }
    for(i = N0 ; i < pat[n].nNext ; i++) subM(pat[n].next[i] , tesu + 1);
}
/******************************************************************************
機能:メイン
引数:なし
戻り値:0
*****************************************************************************/*
int main(void)
{
    int x , y;
    int i , j; /* ループの制御変数 /*
    int n;
    T1 t1;
    for(i = N0 ; i < NYOKO ; i++) t1.x[i] = ax[i].x;
    for(i = N0 ; i < NTATE ; i++) t1.y[i] = ay[i].y;
    for(y = N0 ; y < BY ; y++) {
        for(x = N0 ; x < BX ; x++) b1[y][x] = OFF;
    }
    yokoMove(N0); /* パターンの数を求める /*
    pat = (PAT *)malloc(sizeof(PAT) * nPat);
    if(pat == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(1);
    }
    mode = ON;
    nPat = N0;
    yokoMove(N0); /* 遷移先のIDを求める /*
    hId1 = (int *)malloc(sizeof(int) * nPat);
    if(hId1 == NULL) {
        free(pat);
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(N1);
    }
    hId2 = (int *)malloc(sizeof(int) * nPat);
    if(hId2 == NULL) {
        free(pat);
        free(hId1);
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(N1);
    }
    for(i = N0 ; i < nPat ; i++) { /* 遷移先のIDを添え字番号に変える /*
        pat[i].rec = nPat;
        for(j = N0 ; j < pat[i].nNext ; j++) {
            pat[i].next[j] = search(pat[i].next[j]);
        }
    }
    n = search(getId(t1));
    min = nPat;
    subM(n , N0);
    printf("解答:%d\n" , min);
    for(i = N0 ; i < min + N1 ; i++) {
        printf("--- %d手 ---\n" , i);
        dispZ(pat[hId2[i]].id);
    }
    free(pat); /* 領域開放 /*
    free(hId1);
    free(hId2);
    return(N0);
}


第137回(8月)Ultimate Instant Insanity

/******************************************************************************
Cマガジン2002年5月号電脳クラブ出題
*****************************************************************************/*
#include <stdio.h>
#include <stdlib.h>
#define OFF 0 /* オフ /*
#define ON  1 /* オン /*
#define COL_R 0 /* 赤 /*
#define COL_G 1 /* 緑 /*
#define COL_B 2 /* 青 /*
#define COL_W 3 /* 白 /*
#define COL_Y 4 /* 黄 /*
#define N3 3 /* 3次元 /*
#define N4 4 /* さいころの上下を除いた面の数 /*
#define N5 5 /* さいころの数 /*
#define N6 6 /* さいころの面の数 /*
#define N12 12 /* さいころの置き方の数の半分 /*
#define N24 24 /* さいころの置き方の数 /*
static int t1[][N4] = { /* 上下固定にした時の周りのパターン /*
    1 , 3 , 4 , 5 , /* 0と2を固定。番号の対応はdice参照 /*
    0 , 3 , 2 , 5 , /* 1と4を固定 /*
    0 , 1 , 2 , 4}; /* 3と5を固定 /*
static int dice[][N6] = {
    COL_R , COL_Y , COL_B , COL_G , COL_R , COL_W, /* 0 1 2 /*
    COL_Y , COL_R , COL_W , COL_G , COL_Y , COL_B, /*   3   /*
    COL_R , COL_G , COL_Y , COL_G , COL_B , COL_W, /*   4   /*
    COL_G , COL_W , COL_R , COL_B , COL_B , COL_Y, /*   5   /*
    COL_W , COL_Y , COL_B , COL_R , COL_G , COL_W
};
int t2[N24][N4]; /* さいころの置き方 /*
int f1[N4][N5]; /* 色の使用済みフラグ /*
int count = 0; /* 通りの数 /*
/******************************************************************************
機能:初期化
引数:なし
戻り値:なし
*****************************************************************************/*
void init(void)
{
    int i0 , i1 , i2; /* ループの制御変数 /*
    int n = 0;
    for(i0 = 0 ; i0 < N4 ; i0++) {
        for(i1 = 0 ; i1 < N3 ; i1++) {
            for(i2 = 0 ; i2 < N4 ; i2++) {
                t2[n][i2] = t1[i1][(i0 + i2) % N4]; /* 正回り /*
                t2[n + N12][i2] = t1[i1][(i0 - i2 + N4) % N4]; /* 逆回り /*
            }
            n++;
        }
        for(i1 = 0 ; i1 < N5 ; i1++) f1[i0][i1] = OFF; /* 使用済をオフに /*
    }
}
/******************************************************************************
機能:再帰関数
引数:
  (1) n (I) 何番目のさいころか(0オリジン)
戻り値:なし
*****************************************************************************/*
void sub(int n)
{
    int i , j; /* ループの制御変数 /*
    for(i = 0 ; i < N24 ; i++) {
        if(f1[0][dice[n][t2[i][0]]] == ON) continue; /* 既出色ならスキップ /*
        if(f1[1][dice[n][t2[i][1]]] == ON) continue; /* 既出色ならスキップ /*
        if(f1[2][dice[n][t2[i][2]]] == ON) continue; /* 既出色ならスキップ /*
        if(f1[3][dice[n][t2[i][3]]] == ON) continue; /* 既出色ならスキップ /*
        for(j = 0 ; j < N4 ; j++) f1[j][dice[n][t2[i][j]]] = ON; /* 既出 /*
        if(n < 4) sub(n + 1); /* 次のさいころへ /*
        else count++; /* 5個めならカウントアップ /*
        for(j = 0 ; j < N4 ; j++) f1[j][dice[n][t2[i][j]]] = OFF; /* 戻す /*
    }
}
/******************************************************************************
機能:メイン
引数:なし
戻り値:0
*****************************************************************************/*
int main(void)
{
    int i , j; /* ループの制御変数 /*
    init(); /* 初期化 /*
    for(i = 0 ; i < N3 ; i++) {
        for(j = 0 ; j < N4 ; j++) f1[j][dice[0][t2[i][j]]] = ON; /* 既出 /*
        sub(1); /* 次のさいころへ /*
        for(j = 0 ; j < N4 ; j++) f1[j][dice[0][t2[i][j]]] = OFF; /* 戻す /*
    }
    printf("%d\n" , count); /* 解表示 /*
    return(0);
}


第135回(6月)Iトロミノ

/******************************************************************************
Cマガジン2002年3月号電脳クラブ出題 Iトロミノ
*****************************************************************************/*
#include <stdio.h>
#include <stdlib.h>
#define OFF 0         /* オフ /*
#define ON 1          /* オン /*
#define YSIZE 8       /* 盤のY方向の長さ /*
#define XSIZE 12      /* 盤のX方向の長さ /*
#define N32 32        /* 使用するトロミノの数 /*
#define AKI -1        /* 空いている(未使用)状態 /*
typedef struct {
    int b1[YSIZE][XSIZE];
} BAN;
typedef struct {
    int fx;
    int fy;
} FXY;
int b1[YSIZE][XSIZE]; /* 盤 /*
BAN *b2 = NULL;       /* 既出パターン /*
int nb2 = 0;          /* 既出パターンの数 /*
int xsize1;           /* 盤のX方向の大きさ−1 /*
int ysize1;           /* 盤のY方向の大きさ−1 /*
int xsize2;           /* 盤のX方向の大きさ−2 /*
int ysize2;           /* 盤のY方向の大きさ−2 /*
/******************************************************************************
機能:既出パターンかどうか、鏡像チェックする。
引数:なし
戻り値:なし
*****************************************************************************/*
void check(void)
{
    int i , j , k; /* ループの制御変数 /*
    int x , y; /* 反転前座標 /*
    int x1 , y1; /* 鏡像化による反転後座標 /*
    static FXY fxy[] = {OFF,OFF , ON,OFF , OFF,ON}; /* 鏡像パターン /*
    int a1[N32]; /* 反転後のIトロミノ番号の一致チェック /*
    for(i = 0 ; i < nb2 ; i++) {
        for(k = 0 ; k < sizeof(fxy) / sizeof(fxy[1]) ; k++) {
            for(j = 0 ; j < N32 ; j++) a1[j] = AKI;
            for(y = 0 ; y < YSIZE ; y++) {
                y1 = fxy[k].fy ? y : ysize1 - y;
                for(x = 0 ; x < XSIZE ; x++) {
                    x1 = fxy[k].fx ? x : xsize1 - x;
                    if(a1[b1[y][x]] == AKI) {
                        a1[b1[y][x]] = b2[i].b1[y1][x1];
                    }
                    else if(a1[b1[y][x]] != b2[i].b1[y1][x1]) break;
                }
                if(x != XSIZE) break;
            }
            if(y == YSIZE) return;
        }
    }
    b2 = (BAN *)realloc(b2 , sizeof(BAN) * (nb2 + 1));
    if(b2 == NULL) {
        fprintf(stderr , "realloc error at %d\n" , __LINE__);
        exit(1);
    }
    for(y = 0 ; y < YSIZE ; y++) { /* 新パターンを格納 /*
        for(x = 0 ; x < XSIZE ; x++) {
            b2[nb2].b1[y][x] = b1[y][x];
        }
    }
    nb2++;
    return;
}
/******************************************************************************
機能:再帰関数
引数:
 x (I) X座標
 y (I) Y座標
 n (I) 置く板が何枚目かという数(0オリジン)
戻り値:なし
*****************************************************************************/*
void sub(int x , int y , int n)
{
    int x1 , y1; /* 次の座標 /*
    x1 = x + 1;
    y1 = y;
    if(x1 == XSIZE) {
        x1 = 0;
        y1++;
        if(y1 == YSIZE) {
            check();
            return;
        }
    }
    if(b1[y][x] != AKI) { /* 既に置かれていたら次へ /*
        sub(x1 , y1 , n);
        return;
    }
    if(x > 0 && y > 0) { /* 十字型継ぎ目チェック /*
        if(b1[y][x - 1] != b1[y - 1][x - 1] &&
           b1[y - 1][x] != b1[y - 1][x - 1]) return;
    }
    if(x < xsize2) { /* IトロミノをX方向に置く /*
        if(b1[y][x + 1] == AKI && b1[y][x + 2] == AKI) {
            b1[y][x] = b1[y][x1] = b1[y][x + 2] = n;
            sub(x1 , y1 , n + 1);
            b1[y][x] = b1[y][x1] = b1[y][x + 2] = AKI;
        }
    }
    if(y < ysize2) { /* IトロミノをY方向に置く /*
        if(b1[y + 1][x] == AKI && b1[y + 2][x] == AKI) {
            b1[y][x] = b1[y + 1][x] = b1[y + 2][x] = n;
            sub(x1 , y1 , n + 1);
            b1[y][x] = b1[y + 1][x] = b1[y + 2][x] = AKI;
        }
    }
}
/******************************************************************************
機能:メイン
引数:なし
戻り値:1
*****************************************************************************/*
int main(void)
{
    int x , y; /* ループの制御変数 /*
    for(y = 0 ; y < YSIZE ; y++) {
        for(x = 0 ; x < XSIZE ; x++) b1[y][x] = AKI;
    }
    xsize1 = XSIZE - 1; /* 変数セット /*
    ysize1 = YSIZE - 1;
    xsize2 = XSIZE - 2;
    ysize2 = YSIZE - 2;
    b2 = (BAN *)malloc(sizeof(BAN));
    if(b2 == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(1);
    }
    sub(0 , 0 , 0); /* 座標(0,0)から始める /*
    printf("%d\n" , nb2);
    free(b2);
    return(0);
}


第134回(5月)3乗数の和

/******************************************************************************
Cマガジン2002年2月出題 電脳クラブ 3乗数の和
*****************************************************************************/*
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int x0 , y0 = 1 , y1 , x1 , y2 , x2; /* 1〜3組の小数、大数 /*
    int s0 , s1; /* 和 /*
    int yp0 , xp1 , xp2; /* x0,x1,x2の3乗数 /*
    int min = 2147483647; /* 解の最小値。初期値はint型の最大値 /*
    int minx0 , miny0 , minx1 , miny1 , minx2 , miny2; /* 解の候補 /*
    yp0 = y0 * y0 * y0;
    while(yp0 < min) {
        for(x0 = 1 ; x0 <= y0 ; x0++) { /* 1組目の小数 /*
            s0 = x0 * x0 * x0 + yp0; /* 1組目の和 /*
            y1 = y0 + 1; /* 2組の大数 /*
            for(x1 = x0 - 1 ; x1 > 1 ; x1--) { /* 2組目の小数 /*
                xp1 = x1 * x1 * x1;
                s1 = xp1 + y1 * y1 * y1; /* 2組目の和 /*
                while(s1 <= s0) {
                    if(s1 == s0) {
                        y2 = y1 + 1; /* 3組の大方 /*
                        for(x2 = x1 - 1 ; x2 > 0 ; x2--) { /* 3組目の小数 /*
                            xp2 = x2 * x2 * x2;
                            s1 = xp2 + y2 * y2 * y2; /* 3組目の和 /*
                            while(s1 <= s0) {
                                if(s1 == s0) {
                                    if(s0 < min) { /* 最小なら候補に格納 /*
                                        min = s0;
                                        minx0 = x0;
                                        miny0 = y0;
                                        miny1 = y1;
                                        minx1 = x1;
                                        miny2 = y2;
                                        minx2 = x2;
                                    }
                                }
                                y2++;
                                s1 = xp2 + y2 * y2 * y2; /* 3組目の和 /*
                            }
                        }
                        break;
                    }
                    y1++;
                    s1 = xp1 + y1 * y1 * y1; /* 2組目の和 /*
                }
            }
        }
        y0++; /* 1組の大数 /*
        yp0 = y0 * y0 * y0;
    }
    printf("%d^3 + %d^3 = " , minx2 , miny2); /* 3組目 /*
    printf("%d^3 + %d^3 = " , minx1 , miny1); /* 2組目 /*
    printf("%d^3 + %d^3 = " , minx0 , miny0); /* 1組目 /*
    printf("%d\n" , min); /* 和 /*
    return(1);
}


第133回(4月)見た目は月並みですが

/******************************************************************************
Cマガジン2002年1月号電脳クラブ(見た目は月並みですが)
*****************************************************************************/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OFF 0 /* オフ /*
#define ON  1 /* オン /*
#define YOKO 0 /* 横方向 /*
#define TATE 1 /* 縦方向 /*
#define XY(x , y) ((y) * nxy + (x)) /* 2次元座標を1次元に変換 /*
static char *mon[] = { /* 月の名称 /*
    "JANUARY" , "FEBRUARY" , "MARCH" , "APRIL" ,
    "MAY" , "JUNE" , "JULY" , "AUGUST" ,
    "SEPTEMBER" , "OCTOBER" ,"NOVEMBER" , "DECEMBER"};
typedef struct {
    int monNo; /* 月の番号 /*
    int x;     /* 始点X座標 /*
    int y;     /* 始点Y座標 /*
    int hoko;  /* 置いてある方向 /*
} MM;
typedef struct {
    int monNo; /* あちらの月の番号 /*
    int x;     /* こちらの交差座標 /*
    int y;     /* あちらの交差座標 /*
} JOIN;
typedef struct {
    int x1; /* 最小X座標 /*
    int y1; /* 最小Y座標 /*
    int x2; /* 最大X座標 /*
    int y2; /* 最大Y座標 /*
} AREA;
int nMon; /* 月の数 /*
MM *mm;
JOIN **join; /* 各月間の交差状況 /*
AREA minArea; /* 最小範囲 /*
int *lenm1; /* 月の名称の長さ /*
char *b1; /* 盤(マスごとにアルファベットをセット) /*
int *b2; /* 盤(マスごとに使用する月の数をセット) /*
char *b3; /* 盤(最小パターン) /*
int *fUsed; /* 月使用済みフラグ /*
int min; /* 面積の最小値 /*
int *nJoin; /* 交差状況の数 /*
int nxy = 0; /* 盤の縦、横それぞれの大きさ /*
/******************************************************************************
機能:月を1つ盤に置く
引数:
  (1) n      (I) 何番目か
  (2) monNo  (I) 置く月の番号
  (3) x      (I) 置く月の始点X座標
  (4) y      (I) 置く月の始点Y座標
  (5) hoko   (I) YOKO:横方向、TATE:縦方向
  (6) area   (O) 範囲
戻り値:なし
*****************************************************************************/*
void set(int n , int monNo , int x , int y , int hoko , AREA *area)
{
    int i;
    int len;
    len = lenm1[monNo];
    if(hoko == YOKO) { /* 横方向 /*
        for(i = 0 ; i < len ; i++) {
            b1[XY(x + i , y)] = *(mon[monNo] + i); /* 文字を置く /*
            b2[XY(x + i , y)]++; /* カウントアップ /*
        }
        if(x < area->x1) area->x1 = x; /* X座標最小値を更新 /*
        if(x + len > area->x2) area->x2 = x + len; /* X座標最大値を更新 /*
    }
    else { /* 縦方向 /*
        for(i = 0 ; i < len ; i++) {
            b1[XY(x , y + i)] = *(mon[monNo] + i); /* 文字を置く /*
            b2[XY(x , y + i)]++; /* カウントアップ /*
        }
        if(y < area->y1) area->y1 = y; /* Y座標最小値を更新 /*
        if(y + len > area->y2) area->y2 = y + len; /* Y座標最大値を更新 /*
    }
    mm[n].monNo = monNo;
    mm[n].x = x;
    mm[n].y = y;
    mm[n].hoko = hoko;
    fUsed[monNo] = ON; /* 使用済みフラグをセット /*
}
/******************************************************************************
機能:月を1つ盤から取る
引数:
  (1) monNo  (I) 取る月の番号
  (2) x      (I) 取る月の始点X座標
  (3) y      (I) 取る月の始点Y座標
  (4) hoko   (I) YOKO:横方向、TATE:縦方向
戻り値:なし
*****************************************************************************/*
void unset(int monNo , int x , int y , int hoko)
{
    int i;
    int len;
    len = lenm1[monNo];
    if(hoko == YOKO) { /* 横方向 /*
        for(i = 0 ; i < len ; i++) {
            b2[XY(x + i , y)]--; /* カウントダウン /*
        }
    }
    else { /* 縦方向 /*
        for(i = 0 ; i < len ; i++) {
            b2[XY(x , y + i)]--; /* カウントダウン /*
        }
    }
    fUsed[monNo] = OFF; /* 使用済みフラグを解除 /*
}
/******************************************************************************
機能:月を盤に置けるか調べる
引数:
  (1) monNo  (I) 月の番号
  (2) x      (I) 月の始点X座標
  (3) y      (I) 月の始点Y座標
  (4) hoko   (I) YOKO:横方向、TATE:縦方向
戻り値:OFF:置けない、ON:置ける
*****************************************************************************/*
int okeruka(int monNo , int x , int y , int hoko)
{
    int i;
    int len;
    len = lenm1[monNo];
    if(hoko == YOKO) { /* 横方向 /*
        for(i = 0 ; i < len ; i++) {
            if(b2[XY(x + i , y)] == 0) continue; /* 未使用 /*
            if(b1[XY(x + i , y)] == *(mon[monNo] + i)) continue; /* 同じ /*
            return(OFF); /* 他の文字で使用済みなので置けない /*
        }
    }
    else { /* 縦方向 /*
        for(i = 0 ; i < len ; i++) {
            if(b2[XY(x , y + i)] == 0) continue; /* 未使用 /*
            if(b1[XY(x , y + i)] == *(mon[monNo] + i)) continue; /* 同じ /*
            return(OFF); /* 他の文字で使用済みなので置けない /*
        }
    }
    return(ON); /* 置ける /*
}
/******************************************************************************
機能:再帰関数
引数:
  (1) n    (I) 何番目か
  (2) p1   (I) 交差調査済みの月
  (3) p2   (I) 月の中で交差調査済みの番号
  (4) area (I) 月を置いた範囲
戻り値:なし
*****************************************************************************/*
void sub(int n , int p1 , int p2 , AREA area)
{
    int f1;
    int x , y;
    AREA nxtArea;
    int s;
    int curMonNo; /* 現在の月の番号 /*
    int nxtMonNo; /* 次の月の番号 /*
    int hoko; /* 月の方向 /*
    s = (area.x2 - area.x1) * (area.y2 - area.y1); /* 面積を計算する /*
    if(min <= s) return; /* 既最小値を越えたら探査中止 /*
    if(n == nMon) { /* 12個置いたら /*
        min = s;
        for(y = area.y1 ; y < area.y2 ; y++) {
            for(x = area.x1 ; x < area.x2 ; x++) {
                if(b2[XY(x , y)] > 0) b3[XY(x , y)] = b1[XY(x , y)];
                else b3[XY(x , y)] = ' ';
            }
        }
        minArea.x1 = area.x1;
        minArea.y1 = area.y1;
        minArea.x2 = area.x2;
        minArea.y2 = area.y2;
        return;
    }
    while(p1 < n) {
        curMonNo = mm[p1].monNo; /* 現在の月 /*
        hoko = TATE - mm[p1].hoko; /* 次の月の方向は現在と反対 /*
        while(p2 < nJoin[curMonNo]) {
            nxtMonNo = (*(join + curMonNo) + p2)->monNo; /* 次の月の候補 /*
            if(fUsed[nxtMonNo] == OFF) { /* 候補が未使用ならば /*
                if(mm[p1].hoko == YOKO) { /* 横方向 /*
                    x = mm[p1].x + (*(join + curMonNo) + p2)->x; /* 交差X /*
                    y = mm[p1].y - (*(join + curMonNo) + p2)->y; /* 交差Y /*
                }
                else { /* 縦方向 /*
                    x = mm[p1].x - (*(join + curMonNo) + p2)->y; /* 交差X /*
                    y = mm[p1].y + (*(join + curMonNo) + p2)->x; /* 交差Y /*
                }
                f1 = okeruka(nxtMonNo , x , y , hoko); /* 置けるか判定 /*
                if(f1 == ON) { /* もし置けるならば /*
                    nxtArea.x1 = area.x1;
                    nxtArea.y1 = area.y1;
                    nxtArea.x2 = area.x2;
                    nxtArea.y2 = area.y2;
                    set(n , nxtMonNo , x , y , hoko , &nxtArea); /* 置く /*
                    sub(n + 1 , p1 , p2 + 1 , nxtArea); /* 次へ /*
                    unset(nxtMonNo , x , y , hoko); /* 取る /*
                }
            }
            p2++; /* 次の交差へ /*
        }
        p1++; /* 次の候補月へ /*
        p2 = 0;
    }
}
/******************************************************************************
機能:qsort用の比較関数
引数:
  (1) a (I) 比較対象のポインタ
  (2) b (I) 比較対象のポインタ
戻り値:1:a<b、0:a==b、-1:a>b
*****************************************************************************/*
int cmp(const void *a , const void *b)
{
    if     (strlen(*((char **)a)) <  strlen(*((char **)b))) return(1);
    else if(strlen(*((char **)a)) == strlen(*((char **)b))) return(0);
    else                                                    return(-1);
}
/******************************************************************************
機能:初期化関数
引数:なし
戻り値:なし
*****************************************************************************/*
void init(void)
{
    int i , j;
    int n;
    int x , y;
    nMon = sizeof(mon) / sizeof(mon[0]); /* 月の数 /*
    qsort(mon , nMon , sizeof(char *) , cmp); /* 文字列が長い順にソート /*
    mm = (MM *)malloc(sizeof(MM) * nMon);
    lenm1 = (int *)malloc(sizeof(int) * nMon);
    if(lenm1 == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(0);
    }
    fUsed = (int *)malloc(sizeof(int) * nMon);
    if(fUsed == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(0);
    }
    nJoin = (int *)malloc(sizeof(int) * nMon);
    if(nJoin == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(0);
    }
    for(i = 0 ; i < nMon ; i++) {
        fUsed[i] = OFF;
        lenm1[i] = strlen(mon[i]);
        nxy += lenm1[i];
    }
    nxy = nxy * 2 - 1;
    min = nxy * nxy;
    b1 = (char *)malloc(sizeof(char) * min);
    b2 = (int *)malloc(sizeof(int) * min);
    b3 = (char *)malloc(sizeof(char) * min);
    for(y = 0 ; y < nxy ; y++) {
        for(x = 0 ; x < nxy ; x++) b2[XY(x , y)] = 0;
    }
    join = (JOIN **)malloc(sizeof(JOIN **) * nMon);
    if(join == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(0);
    }
    for(i = 0 ; i < nMon ; i++) {
        n = 0;
        *(join + i) = (JOIN *)malloc(sizeof(JOIN));
        if(*(join + i) == NULL) {
            fprintf(stderr , "malloc error at %d\n" , __LINE__);
            exit(0);
        }
        for(j = 0 ; j < nMon ; j++) {
            if(i == j) continue;
            for(x = 0 ; x < lenm1[i] ; x++) {
                for(y = 0 ; y < lenm1[j] ; y++) {
                    if(*(mon[i] + x) != *(mon[j] + y)) continue; /* 共有? /*
                    *(join + i) =
                        (JOIN *)realloc(*(join + i) , sizeof(JOIN) * (n + 1));
                    if(*(join + i) == NULL) {
                        fprintf(stderr , "realloc error at %d\n" , __LINE__);
                        exit(0);
                    }
                    (*(join + i) + n)->monNo = j;
                    (*(join + i) + n)->x = x;
                    (*(join + i) + n)->y = y;
                    n++;
                }
            }
        }
        nJoin[i] = n;
    }
}
/******************************************************************************
機能:メイン
引数:なし
戻り値:0
*****************************************************************************/*
int main(void)
{
    int x , y;
    AREA area;
    int i;
    init();
    area.x1 = nxy / 2;
    area.y1 = area.x1;
    area.x2 = area.x1 + 1;
    area.y2 = area.x2;
    set(0 , 0 , area.x1 , area.y1 , YOKO , &area); /* 9月をセット /*
    sub(1 , 0 , 0 , area); /* 次へ /*
    printf("面積:%d\n" , min); /* 解答表示 /*
    for(y = minArea.y1 ; y < minArea.y2 ; y++) {
        for(x = minArea.x1 ; x < minArea.x2 ; x++)
            printf("%c" , b3[XY(x , y)]);
        printf("\n");
    }
    free(mm);
    free(lenm1);
    free(fUsed);
    free(nJoin);
    free(b1);
    free(b2);
    free(b3);
    for(i = 0 ; i < nMon ; i++) free(join[i]);
    free(join);
    return(0);
}


第132回(3月)素数で割り切る素数の和

/******************************************************************************
Cマガジン2001年12月号出題(素数で割り切る素数の和)
*****************************************************************************/*
#include <stdio.h>
#include <stdlib.h>
#define OFF 0 /* オフ /*
#define ON  1 /* オン /*
#define N2 2 /* 最小の偶数素数 /*
#define N3 3 /* 最小の奇数素数 /*
#define NK 3 /* 求める解の数 /*
#define NN 10000 /* 素数の和を格納する配列の要素の最大値+1 /*
int nSosu = 0; /* 素数の数 /*
int *sosu = NULL; /* 素数テーブル /*
/******************************************************************************
機能:素数がどうかチェックする。
引数:
 (1) n (I) チェック対象の数
戻り値:OFF:非素数、ON:素数
*****************************************************************************/*
int check(int n)
{
    int i; /* ループの制御変数 /*
    for(i = 0 ; i < nSosu ; i++) {
        if((n % sosu[i]) == 0) return(OFF); /* 素数で割りきれれば非素数 /*
        if(sosu[i] * sosu[i] > n) break;
    }
    sosu = (int *)realloc(sosu , sizeof(int) * (nSosu + 1));
    if(sosu == NULL) {
        fprintf(stderr , "realloc error at %d\n" , __LINE__);
        exit(0);
    }
    sosu[nSosu++] = n; /* 素数だったら素数テーブルに登録する /*
    return(ON);
}
/******************************************************************************
機能:メイン
引数:なし
戻り値:0
*****************************************************************************/*
int main(void)
{
    int n0; /* 対象の数 /*
    int n2 = N3; /* 対象の数に直近の素数候補 /*
    int f0; /* n0が素数かどうかのフラグ OFF:非素数、ON:素数/*
    int f2; /* n2が素数かどうかのフラグ OFF:非素数、ON:素数/*
    int nd = 1; /* 素数の和を格納する配列の要素数 /*
    int *sum; /* 素数の和 /*
    int count = 0; /* 求まった解の数 /*
    int t1; /* 割り算の余り /*
    int i; /* ループの制御変数 /*
    sum = (int *)malloc(sizeof(int) * nd);
    if(sum == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(0);
    }
    sum[0] = N2;
    n0 = n2 + N2;
    sosu = (int *)malloc(sizeof(int)); /* ←ご指摘箇所 /*
    f2 = check(n2);
    while(count < NK) { /* 解がNK個見つかるまでループする /*
        f0 = check(n0); /* 対象の数が素数かどうかチェックする /*
        if(f2 == ON) { /* 対象の数−2が素数なら加算する /*
            sum[0] += n2;
            for(i = 0 ; i < nd - 1 ; i++) {
                sum[i + 1] += sum[i] / NN;
                sum[i] %= NN;
            }
            if(sum[nd - 1] >= NN) { /* 和が納まらなくなったら領域を拡大する /*
                sum = (int *)realloc(sum , sizeof(int) * (nd + 1));
                if(sum == NULL) {
                    fprintf(stderr , "realloc error at %d\n" , __LINE__);
                    exit(0);
                }
                sum[nd] = sum[nd - 1] / NN;
                sum[nd - 1] %= NN;
                nd++;
            }
        }
        if(f0 == ON) {
            t1 = sum[nd - 1] % n0;
            for(i = nd - 2 ; i >= 0 ; i--) t1 = (sum[i] + t1 * NN) % n0;
            if(t1 == 0) { /* 割った余りがゼロなら /*
                printf("%d\n" , n0); /* 解を表示 /*
                count++;
            }
        }
        n2 = n0;
        f2 = f0;
        n0 += 2;
    }
    free(sum);
    free(sosu);
    return(0);
}


第131回(2月)チェス盤の分割

/******************************************************************************
Cマガジン2001年11月号出題 チェス盤の分割
*****************************************************************************/*
#include <stdio.h>
#include <stdlib.h>
#define OFF 0 /* オフ /*
#define ON  1 /* オン /*
#define NON 0 /* どちらでもない状態 /*
#define BAN_A 1 /* 2片のうちのA /*
#define BAN_B 2 /* 2片のうちのB /*
#define NN 10 /* チェス盤の大きさ /*
int nx; /* NN - 2 /*
int ny; /* NN / 2 /*
int nx1; /* nx - 1 /*
int ny1; /* ny - 1 /*
int nxy2; /* NN * NN / 2 - NN /*
int nn1; /* NN - 1 /*
int b1[NN][NN]; /* チェス盤 BAN_A=A片 BAN_B=B片 NON=どちらでもない /*
int b2[NN][NN]; /* チェス盤 OFF=未チェック ON=チェック済み /*
int count = 0; /* パターンの数 /*
/******************************************************************************
機能:チェックの再帰関数
   自分と同じ片、あるいはまだ置いてない場所を辿り、端まで到達できるか?
引き数:
  (1) x  (I) : X座標
  (2) y  (I) : Y座標
  (3) p1 (I) : 相手の片の種類
  (4) rx (I) : 到達すべきX座標
戻り値:OFF=駄目 ON=OK
*****************************************************************************/*
int check_sub(int x , int y , int p1 , int rx)
{
    if(b1[y][x] == p1) return(OFF);
    if(x == rx) return(ON); /* 自分の片へ達したら戻る /*
    if(b2[y][x] == ON) return(OFF);
    b2[y][x] = ON;
    if(x >   0) { /* X座標を+1して次へ /*
        if(check_sub(x - 1 , y     , p1 , rx) == ON) return(ON);
    }
    if(x < nx1) { /* X座標を−1して次へ /*
        if(check_sub(x + 1 , y     , p1 , rx) == ON) return(ON);
    }
    if(y >   0) { /* Y座標を−1して次へ /*
        if(check_sub(x     , y - 1 , p1 , rx) == ON) return(ON);
    }
    if(y < nn1) { /* Y座標を+1して次へ /*
        if(check_sub(x     , y + 1 , p1 , rx) == ON) return(ON);
    }
    return(OFF);
}
/******************************************************************************
機能:題意を満たすかどうかのチェック
引き数:
  (1) x  (I) : X座標
  (2) y  (I) : Y座標
  (3) p1 (I) : 相手の片の種類
  (4) rx (I) : 到達すべきX座標
戻り値:OFF=駄目 ON=OK
*****************************************************************************/*
int check(int x , int y , int p1 , int rx)
{
    int x1 , y1; /* 座標 /*
    for(y1 = 0 ; y1 < NN ; y1++) { /* チェス盤全体を未チェックにセット /*
        for(x1 = 0 ; x1 < nx ; x1++) b2[y1][x1] = OFF;
    }
    return(check_sub(x , y , p1 , rx));
}
/******************************************************************************
機能:再帰関数
   1箇所ずつ、AまたはBをセットしていく。
引き数:
  (1) x (I) : X座標
  (2) y (I) : Y座標
  (3) f1 (I) 上下反転鏡像チェック済みフラグ OFF=未チェック ON=チェック済み
戻り値:なし
*****************************************************************************/*
void sub(int x , int y ,int f1)
{
    int x2 , y2; /* 次の座標 /*
    int x3; /* 座標 /*
    int sts; /* 戻り値を格納 /*
    if(x == 0 && f1 == OFF) { /* 上下反転鏡像チェック /*
        for(x3 = 0 ; x3 < nx ; x3++) {
            if(b1[y - 1][x3] == BAN_A && b1[y - 1][nx1 - x3] == BAN_A) {
                f1 = ON;
                break;
            }
            if(b1[y - 1][x3] == BAN_B && b1[y - 1][nx1 - x3] == BAN_B) return;
        }
    }
    if(y == ny) { /* チェス盤が全て埋まったら題意を満たすかチェック /*
        for(x3 = 0 ; x3 < nx ; x3++) {
            if(b1[ny1][x3] == BAN_A) sts = check(x3 , ny1 , BAN_B , 0);
            else sts = check(x3 , ny1 , BAN_A , nx1);
            if(sts == OFF) return;
        }
        count++;
        return;
    }
    x2 = x + 1; /* 次の手の座標を求める /*
    y2 = y;
    if(x2 == nx) {
        x2 = 0;
        y2++;
    }
    sts = ON;
    b1[y][x] = BAN_A; /* その場所をA片にする(対照位置はB片) /*
    b1[nn1 - y][nx1 - x] = BAN_B;
    if(y > 0) { /* 置けるか(孤立するB片が存在するかチェック) /*
        if(b1[y - 1][x] == BAN_B) sts = check(x , y - 1 , BAN_A , nx1);
    }
    if(sts == ON) sub(x2 , y2 , f1); /* A片を置いて次へ /*
    sts = ON;
    b1[y][x] = BAN_B; /* その場所をB片にする(対照位置はA片) /*
    b1[nn1 - y][nx1 - x] = BAN_A;
    if(y > 0) { /* 置けるか(孤立するA片が存在するかチェック) /*
        if(b1[y - 1][x] == BAN_A) sts = check(x , y - 1 , BAN_B , 0);
    }
    if(sts == ON) sub(x2 , y2 , f1); /* B片を置いて次へ /*
    b1[y][x] = b1[nn1 - y][nx1 - x] = NON; /* 元に戻す/*
}
/******************************************************************************
機能:メイン。チェス盤の初期化など
引き数:なし
戻り値:0
*****************************************************************************/*
int main(void)
{
    int x , y; /* 座標 /*
    nx = NN - 2; /* 定数の設定 /*
    ny = NN / 2; /* 定数の設定 /*
    nx1 = nx - 1; /* 定数の設定 /*
    ny1 = ny - 1; /* 定数の設定 /*
    nxy2 = (NN * NN) / 2 - NN; /* 定数の設定 /*
    nn1 = NN - 1; /* 定数の設定 /*
    for(y = 0 ; y < ny ; y++) { /* チェス盤の初期化 /*
        for(x = 0 ; x < nx ; x++) {
            b1[y][x] = b1[ny + y][x] = NON;
        }
    }
    b1[0][0] = BAN_A;
    b1[nn1][nx1] = BAN_B;
    sub(1 , 0 , OFF);
    printf("%d\n" , count); /* 解答表示 /*
    return(0);
}


第130回(1月)こだ割り数

/* C MAGAZINE 2001.10電脳クラブ出題 こだ割り数 /*
#include <stdio.h>
#include <stdlib.h>
int max = -1; /* 最大値の桁数 /*
int *m1; /* 最大値 /*
#define N1 10 /* 10進法の10 /*
#define N2 10000  /* N3 / N1 /*
#define N3 100000 /* ロング数の個々の要素の最大値+1 /*
#define N5 5 /* ロング数の個々の要素の桁数 /*
/******************************************************************************
機能:再帰ルーチン
引数:
  (1) s1 (I) ここまでの数(n−1)桁
  (2) n  (I) 今回の桁数
戻り値:なし
*****************************************************************************/*
void sub(int *s1 , int n)
{
    int i , j; /* ループの制御変数 /*
    int *s2; /* n桁の数 /*
    int k; /* n桁におけるロング数の要素の数 /*
    int a; /* 余り /*
    k = (n - 1) / N5;
    s2 = (int *)malloc(sizeof(int) * (k + 1));
    if(s2 == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        return;
    }
    if(((n - 1) % N5) == 0) s1[k] = 0; /* 要素数が増えた場合、0をセット /*
    for(i = 0 ; i < N1 ; i++) { /* 最下位の桁追加(0〜9) /*
        for(j = k ; j > 0 ; j--)
            s2[j] = (s1[j] % N2) * N1 + s1[j - 1] / N2; /* 10倍する /*
        s2[0] = (s1[0] % N2) * N1 + i; /* 最下位桁 /*
        a = s2[k] % n;
        for(j = k - 1 ; j >= 0 ; j--) a = (s2[j] + a * N3) % n;
        if(a != 0) continue; /* 割り切れない場合にスキップ /*
        if(n >= max) { /* 最大値だった場合の処理 /*
            max = n;
            m1 = (int *)realloc(m1 , sizeof(int) * (k + 1));
            if(m1 == NULL) {
                fprintf(stderr , "realloc error at %d\n" , __LINE__);
                free(s2);
                return;
            }
            for(j = 0 ; j < k + 1 ; j++) m1[j] = s2[j]; /* 解答を退避 /*
        }
        sub(s2 , n + 1);
    }
    free(s2);
}
/******************************************************************************
機能:メイン
引数:なし
戻り値:0
*****************************************************************************/*
int main(void)
{
    int i , j; /* ループの制御変数 /*
    int k; /* n桁におけるロング数の要素の数 /*
    int d;
    int s1[1];
    m1 = (int *)malloc(sizeof(int)); /* 解答のロング数のメモリ確保 /*
    if(m1 == NULL) {
        fprintf(stderr , "malloc error at %d\n" , __LINE__);
        exit(0);
    }
    for(i = 1 ; i < N1 ; i++) {
        s1[0] = i; /* 最上位桁の値(1〜9) /*
        sub(s1 , 2);
    }
    k = (max - 1) / N5; /* 解答のロング数の要素の数 /*
    printf("%d" , m1[k]);
    for(i = k - 1 ; i >= 0 ; i--) {
        d = N2;
        for(j = 0 ; j < N5 ; j++) { /* 5桁ごとに解答表示 /*
            printf("%1d" , (m1[i] / d) % N1);
            d /= N1;
        }
    }
    printf("\n");
    free(m1);
    return(0);
}