Last Update: Jul.8,2003

C Source Library

「LSI C-86 Ver.3.30c 試食版」、「Borland C++ 5.5」、「Microsoft Visual C++ 6.0」でコンパイル出来ます。

■ パズルを解く 2

/*
 *  ship.c : パズルを解く2
 *
 *      Copyright (c) 2001, 2003 AOK.
 *
 *          2001.05.23 - 初版
 *          2001.07.08 - 2版
 *
 *  大きな川があり、一艘の船がある。左岸には男が3人と女が
 *  3人いる。全員が右岸に渡らなければならない。船には一度
 *  に2人までしか乗れない。男女とも船の運転ができる。しか
 *  し女より男の人数が多いと女は男たちに殺されてしまう。
 *
 */

#include <stdlib.h>
#include <stdio.h>

#define MAX_M   3   /* 男性の人数 */
#define MAX_F   3   /* 女性の人数 */

typedef struct _NODE {
    int no;           /* ノードの深さ */
    int m1, f1;       /* 左岸の男女の数 */
    int m2, f2;       /* 右岸の男女の数 */
    struct _NODE *nd; /* 次ノードのアドレス */
} NODE;

NODE f = { 0,MAX_M,MAX_F,0,0,NULL }; /* 最初のノード */

/* 女性が男性と同数か多いとき真 */
#define isok(n) ( ((n->f1==0)||(n->f1>=n->m1))  \
                &&((n->f2==0)||(n->f2>=n->m2)) )

/* 遡ってノードに同じ状態がないとき真(ループ回避) */
int hist(NODE *n)
{
    NODE *p = &f;
    while (p->nd != NULL) {
        if (   (n->no % 2 == p->no % 2)
            && (p->m1 == n->m1)
            && (p->f1 == n->f1) )
                return 0;
        p = p->nd;
    }
    return 1;   
}

/* 最初からの手順を表示 */
void display(void)
{
    NODE *p = &f; int i;
    do {
        printf("(%2d) ", p->no);
        for (i=0; i<p->m1; i++) printf("●");
        for (i=0; i<p->f1; i++) printf("○");
        if (p->no % 2) printf(" → "); else printf(" ← ");
        for (i=0; i<p->m2; i++) printf("●");
        for (i=0; i<p->f2; i++) printf("○");
        putchar('\n');
        p = p->nd;
    } while (p != NULL);
    putchar('\n');
}

/* 船で移動(バックトラック法)*/
void turn(NODE *n)
{
    int i, j;
    NODE *p = (NODE *)calloc(1, sizeof(NODE)); /* 次ノード用のメモリを確保 */
    p->no = n->no + 1; n->nd = p;
    if (p->no % 2) { /* 左岸→右岸 */
        for (i=0; i<=n->m1; i++) { /* 乗船パターン */
            for (j=0; j<=n->f1; j++) {
                if (i+j == 0) continue; if (i+j > 2) break;
                p->m1 = n->m1 - i; p->f1 = n->f1 - j;
                p->m2 = n->m2 + i; p->f2 = n->f2 + j;
                if ((p->m2 == MAX_M) && (p->f2 == MAX_F)) {
                    display(); /* 右岸へ渡りきった */
                } else {
                    if (isok(p) && hist(p)) turn(p);
                }
            }
        }
    } else { /* 左岸←右岸 */
        for (i=0; i<=n->m2; i++) { /* 乗船パターン */
            for (j=0; j<=n->f2; j++) {
                if (i+j == 0) continue; if (i+j > 2) break;
                p->m2 = n->m2 - i; p->f2 = n->f2 - j;
                p->m1 = n->m1 + i; p->f1 = n->f1 + j;
                if (isok(p) && hist(p)) turn(p);
            }
        }
    }
    n->nd = NULL;
    free(p); /* 確保したメモリを解放 */
}

/* メインルーチン */
int main(void)
{
    turn(&f); /* 移動開始 */
    return 0;
}

/* --- 実行結果 -------------------------------------

( 0) ●●●○○○ ← 
( 1) ●●○○ → ●○
( 2) ●●○○○ ← ●
( 3) ○○○ → ●●●
( 4) ●○○○ ← ●●
( 5) ●○ → ●●○○
( 6) ●●○○ ← ●○
( 7) ●● → ●○○○
( 8) ●●● ← ○○○
( 9) ● → ●●○○○
(10) ●○ ← ●●○○
(11)  → ●●●○○○

( 0) ●●●○○○ ← 
( 1) ●●○○ → ●○
( 2) ●●○○○ ← ●
( 3) ○○○ → ●●●
( 4) ●○○○ ← ●●
( 5) ●○ → ●●○○
( 6) ●●○○ ← ●○
( 7) ●● → ●○○○
( 8) ●●● ← ○○○
( 9) ● → ●●○○○
(10) ●● ← ●○○○
(11)  → ●●●○○○

( 0) ●●●○○○ ← 
( 1) ●○○○ → ●●
( 2) ●●○○○ ← ●
( 3) ○○○ → ●●●
( 4) ●○○○ ← ●●
( 5) ●○ → ●●○○
( 6) ●●○○ ← ●○
( 7) ●● → ●○○○
( 8) ●●● ← ○○○
( 9) ● → ●●○○○
(10) ●○ ← ●●○○
(11)  → ●●●○○○

( 0) ●●●○○○ ← 
( 1) ●○○○ → ●●
( 2) ●●○○○ ← ●
( 3) ○○○ → ●●●
( 4) ●○○○ ← ●●
( 5) ●○ → ●●○○
( 6) ●●○○ ← ●○
( 7) ●● → ●○○○
( 8) ●●● ← ○○○
( 9) ● → ●●○○○
(10) ●● ← ●○○○
(11)  → ●●●○○○

 ------------------------------------------------- */