/* * family.c : パズルを解く(再帰を利用) * * Copyright (c) 2000, 2001 AOK. * * 2000.9.14 - 4版 * 2001.5.21 - 7版(全パターンを出力するように修正) * 2001.5.24 - 9版(素数の性質を利用したものに変更) * * ある家族、父、母、娘が2人、息子が2人、召使い、犬がいます。 * この家族が大きな川を渡ろうとしています。船は一つしかありませ * ん。しかも乗れるのは2人だけで一人は運転手がいります。運転出 * 来るのは、父、母、召使いだけです。父は母がいないと息子を殺し、 * 母は父がいないと娘を殺し、犬は召使いがいないと家族を殺します。 * どうしたら川を渡れるかな? 何回往復してもいい。 * */ #include <stdio.h> #include <stdlib.h> #define numof(x) (sizeof(x)/sizeof(x[0])) #define FT 2 #define MT 3 #define SN 5 #define DT 7 #define SL 11 #define DG 13 #define AL (FT*MT*SN*SN*DT*DT*SL*DG) /* (家族全員) */ typedef struct _STAT { int no; /* ステージ数 */ long here; /* 此岸 */ long ship; /* 船上 */ long there; /* 対岸 */ struct _STAT *next; } STAT; /* 最初の此岸・船上・対岸の状態 */ STAT start = { 0, AL, 1, 1, NULL }; const long pt[] = { /* 船上パターン */ FT , MT , SL , FT*MT, FT*DT, FT*SL, MT*SN, MT*SL, SL*SN, SL*DT, SL*DG, }; /* 状態の表示用 */ void output(long s) { if (s % FT == 0) printf("父"); if (s % MT == 0) printf("母"); if (s % SN == 0) printf("息"); if (s % (SN*SN) == 0) printf("息"); if (s % DT == 0) printf("娘"); if (s % (DT*DT) == 0) printf("娘"); if (s % SL == 0) printf("召"); if (s % DG == 0) printf("犬"); } /* すべての条件の判定 */ int ok(long s) { /* 父は母がいないと息子達を殺す */ if (!(s % (FT*SN)) && (s % MT)) return 0; /* 母は父がいないと娘達を殺す */ if (!(s % (MT*DT)) && (s % FT)) return 0; /* 犬は召使いがいないと家族を殺す */ if (!(s % DG) && (s % SL) && (s != DG)) return 0; return 1; } /* 履歴のパターンと照合 */ int history(STAT *t) { STAT *p = &start; while (p->next != NULL) { if (t->no % 2) { if (p->here == t->here) return 0; } else { if (p->there == t->there) return 0; } p = p->next; } return 1; } int check(STAT *t) { if (t->no % 2) return (ok(t->here) && ok(t->there * t->ship) && history(t)); return (ok(t->there) && ok(t->here * t->ship) && history(t)); } void listout(void) { STAT *p = &start; int c; do { c = p->no % 2; printf("(%2d) ", p->no); output(p->here); if (c) printf("→"); else printf("←"); putchar('['); output(p->ship); putchar(']'); if (c) printf("→"); else printf("←"); output(p->there); putchar('\n'); p = p->next; } while (p != NULL); putchar('\n'); } /* 船で輸送(再帰関数) */ void shipping(STAT *p) { int i; STAT *t = (STAT *)calloc(1, sizeof(STAT)); t->no = p->no + 1; if (t->no % 2) { /* 此岸 → 船 */ for (i=0; i<numof(pt); i++) { t->here = p->here * p->ship; t->there = p->there; if (t->here % pt[i] == 0) { t->here /= pt[i]; t->ship = pt[i]; if (check(t)) { p->next = t; shipping(t); } } } } else { /* 船 ← 対岸 */ for (i=0; i<numof(pt); i++) { t->there = p->there * p->ship; t->here = p->here; if (t->there == AL) { /* 家族全員が対岸 */ listout(); break; } if (t->there % pt[i] == 0) { t->there /= pt[i]; t->ship = pt[i]; if (check(t)) { p->next = t; shipping(t); } } } } p->next = NULL; free(t); } /* メインルーチン */ int main() { shipping(&start); /* 輸送開始 */ return 0; }
→ 実行結果