0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Kinx アルゴリズム - 宣教師と人食い人種

Posted at

Kinx アルゴリズム - 宣教師と人食い人種

はじめに

「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。「プログラム=アルゴリズム+データ構造」。アルゴリズムの実装例をご紹介。

元ネタは「C言語による(30年経っても)最新アルゴリズム事典」。今回は宣教師と人食い人種です。

最新アルゴリズム事典にはこういうのも結構載ってる。パズル的な。

これは割と最近書いた。なぜって、解を表示するところが printf のフォーマット書式を駆使しててその移植が面倒な感じになっていたから。

宣教師と人食い人種

Wikipedia より

宣教師と先住民
3人の宣教師と3人の先住民が川岸にいる。川には2人まで乗れるボートが1艘ある。
ボートを漕げるのは宣教師のうちの1人と、先住民のうちの1人だけである。どちらかの岸で先住民の数が宣教師の数より多くなると、先住民は反旗を翻し宣教師に襲い掛かる。全員が無事に対岸に渡るにはどうしたらよいか?

ソースコード

const M = 3;
const C = 3;
const B = 2;

var np, solution;
var mb = [], cb = [],
    mh = [], ch = [], flag = [];
var i = 0;
var mmm = "MMMMMMMMMM", ccc = "CCCCCCCCCC";

function found(n)  /* Display a solution */
{
    var i;

    System.println("Solution %d" % ++solution);
    for (i = 0; i <= n; i++) {
        var m1 = mmm.subString(0, mh[i]);
        var m2 = mmm.subString(0, M-mh[i]);
        var c1 = ccc.subString(0, ch[i]);
        var c2 = ccc.subString(0, C-ch[i]);
        System.println(("%4d  %-%{M}s %-%{C}s  /  %-%{M}s %-%{C}s") % i % m1 % c1 % m2 % c2);
    }
}

function tryit()  /* Try it recursve */
{
    var j, m, c;

    i++;
    for (j = 1; j < np; j++) {
        if (i & 1) {  /* Go there in odd number. */
            m = mh[i - 1] - mb[j];  c = ch[i - 1] - cb[j];
        } else {      /* Come here in even number. */
            m = mh[i - 1] + mb[j];  c = ch[i - 1] + cb[j];
        }
        if (m < 0 || c < 0 || m > M || c > C ||
                (flag[m][c] & (1 << (i & 1)))) continue;
        mh[i] = m;  ch[i] = c;
        if (m == 0 && c == 0) found(i);
        else {
            flag[m][c] |= 1 << (i & 1);  tryit();
            flag[m][c] ^= 1 << (i & 1);
        }
    }
    i--;
}

var m, c;

np = 0;
for (m = 0; m <= B; m++) for (c = 0; c <= B - m; c++)
    if (m == 0 || m >= c) {
        mb[np] = m;  cb[np] = c;  np++;
    }
for (m = 0; m <= M; m++) for (c = 0; c <= C; c++)
    if ((m > 0 && m < c) || (m < M && M - m < C - c))
        flag[m][c] |= 1 | 2;
mh[0] = M;  ch[0] = C;  flag[M][C] |= 1;
solution = 0;  tryit();
if (solution == 0) System.println("No solutions.");

結果

Solution 1
   0  MMM CCC  /
   1  MMM C    /      CC
   2  MMM CC   /      C
   3  MMM      /      CCC
   4  MMM C    /      CC
   5  M   C    /  MM  CC
   6  MM  CC   /  M   C
   7      CC   /  MMM C
   8      CCC  /  MMM
   9      C    /  MMM CC
  10      CC   /  MMM C
  11           /  MMM CCC
Solution 2
   0  MMM CCC  /
   1  MMM C    /      CC
   2  MMM CC   /      C
   3  MMM      /      CCC
   4  MMM C    /      CC
   5  M   C    /  MM  CC
   6  MM  CC   /  M   C
   7      CC   /  MMM C
   8      CCC  /  MMM
   9      C    /  MMM CC
  10  M   C    /  MM  CC
  11           /  MMM CCC
Solution 3
   0  MMM CCC  /
   1  MM  CC   /  M   C
   2  MMM CC   /      C
   3  MMM      /      CCC
   4  MMM C    /      CC
   5  M   C    /  MM  CC
   6  MM  CC   /  M   C
   7      CC   /  MMM C
   8      CCC  /  MMM
   9      C    /  MMM CC
  10      CC   /  MMM C
  11           /  MMM CCC
Solution 4
   0  MMM CCC  /
   1  MM  CC   /  M   C
   2  MMM CC   /      C
   3  MMM      /      CCC
   4  MMM C    /      CC
   5  M   C    /  MM  CC
   6  MM  CC   /  M   C
   7      CC   /  MMM C
   8      CCC  /  MMM
   9      C    /  MMM CC
  10  M   C    /  MM  CC
  11           /  MMM CCC

おわりに

解の表示以外はほぼ C 言語版と同じ。解の表示のところはマルっと書き換えている。元々がどうなっていたかここに示しておこう。元々の C 言語では以下のように実装されている。

#define M  3  /* 宣教師の数 */
#define C  3  /* 人食い人の数 */

void found(int n)  /* 解の表示 */
{
    int i;
    static char mmm[] = "MMMMMMMMMM", ccc[] = "CCCCCCCCCC";

    printf("解 %d\n", ++solution);
    for (i = 0; i <= n; i++) {
        printf("%4d  %-*.*s %-*.*s  /  %-*.*s %-*.*s\n",
            i, M, mh[i], mmm, C, ch[i], ccc,
               M, M - mh[i], mmm, C, C - ch[i], ccc);
    }
}

これはこのままでは使えないので、こう書き換えている。

const M = 3;
const C = 3;

function found(n)  /* Display a solution */
{
    var i;

    System.println("Solution %d" % ++solution);
    for (i = 0; i <= n; i++) {
        var m1 = mmm.subString(0, mh[i]);
        var m2 = mmm.subString(0, M-mh[i]);
        var c1 = ccc.subString(0, ch[i]);
        var c2 = ccc.subString(0, C-ch[i]);
        System.println(("%4d  %-%{M}s %-%{C}s  /  %-%{M}s %-%{C}s") % i % m1 % c1 % m2 % c2);
    }
}

仕方ないよね。

では、また次回。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?