川渡り問題(パズル)

 投稿者:山中和義  投稿日:2015年 3月 3日(火)14時09分42秒
  問題 宣教師と先住民
3人の宣教師と3人の先住民が川を渡ることになりました。
川には、2人乗りのボートが1そうしかありません。
どのようなときでも先住民の数が宣教師の数よりも多いと、宣教師は襲われてしまいます。
なお、全員がボートを漕ぐことができます。
また、岸に着いたとき全員がボートを降ります。
6人が安全に川を渡る最短手順を考えてください。

考察
最短手順
・n人ずつ、(n-1)人乗りのとき
 3人ずつ、2人乗りのとき、11回
 4人ずつ、3人乗りのとき、9回
 5人ずつ、4人乗りのとき、7回
 6人ずつ、5人乗りのとき、7回
   :

 n≧7の場合、5回
  1: nAna[(n-1)a]→
  2: ←[a](n-1)a
  3: nA2a[(n-2)A]→
  4: ←[Aa](n-2)A(n-2)a
  5: 3A3a[3A3a]→

  最短手順の考察
  ボートに乗るときに制限がなければ、
  (n-1)人が渡り1人が戻るとすると、(n-2)人ずつ渡ることになる。
  たとえばn=7の場合、(2n)÷(n-2)は商2 余り4 より、2×2+1=5回が必要になる。(必要性)
  その実例が存在する。(十分性)

  n n-2 (2n)÷(n-2) 回数
  -------------------------------
  3 1  6      5×2+1=11
  4 2  4      3×2+1=7
  5 3  3余り1    3×2+1=7
  6 4  4      3×2+1=7
  7 5  2余り4    2×2+1=5

・4人乗りの場合
 n人ずつ(n≧5)のとき、(2n-3)回
  1: nAna[AAaa]→
  2: ←[Aa]AAaa
  3: (n-1)A(n-1)a[AAaa]→
  4: ←[Aa]2A2a
      :
  2k-1: 3A3a[AAaa]→
    2k: ←[Aa](n-1)A(n-1)a
  +1: 2A2a[AAaa]→
 k往復(nが2になるまで)と最後に1回なので、2(n-2)+1=2n-3
(終わり)


類題 嫉妬深い夫
3組の夫婦が川を渡ることになりました。ボートには2人しか乗ることができません。
どの夫も嫉妬深く、彼自身が一緒にいない限り、ボートでも岸でも妻が他の男といることを許しません。
なお、6人ともボートを漕ぐことができます。
また、岸に着いたとき全員が舟を降ります。
3組の夫婦が川を渡る最短手順を考えてください。
答え
M=3、N=3、K=2として、
 1: AAAaaa(aa)→
 2: ←(a)aa
 3: AAAaa(aa)→
 4: ←(a)aaa
 5: AAAa(AA)→
 6: ←(Aa)AAaa
 7: AAaa(AA)→
 8: ←(a)AAAa
 9: aaa(aa)→
 10: ←(a)AAAaa
 11: aa(aa)→
より、
 1: ABCabc(ab)→
 2: ←(a)ab
 3: ABCac(ac)→
 4: ←(a)abc
 5: ABCa(BC)→
 6: ←(Bb)BCbc
 7: ABab(AB)→
 8: ←(c)ABCc
 9: abc(ab)→
 10: ←(a)ABCab
 11: ac(ac)→
(終わり)



LET M=3 !m人の宣教師
LET N=3 !n人の先住民
LET K=2 !k人乗りの舟

DIM S$((M+1)*(N+1)) !条件を満たす岸の状態
LET D=0
FOR X=0 TO M
   FOR Y=0 TO N
      IF X=0 OR X>=Y THEN !条件を満たす
         LET D=D+1
         LET S$(D)=REPEAT$("A",X)&REPEAT$("a",Y)
      END IF
   NEXT Y
NEXT X

PUBLIC NUMERIC C !解の数
LET C=0
DIM A(50) !手順(舟の乗せ方)
DIM B(0 TO 50) !こちらの岸の状態
LET B(0)=D
CALL try(1,A,B, M,N,K, D,S$)
IF C=0 THEN PRINT "解なし"

END

EXTERNAL SUB try(P,A(),B(), M,N,K, D,S$()) !バックトラック法で検索する
FOR i=1 TO D !舟に乗る
   LET T=LEN(S$(i))
   IF T>=1 AND T<=K THEN !k人乗りの舟 ※岸の部分集合
      LET L$=S$(B(P-1)) !こちらの岸の状態
      LET X=POS(L$,S$(i))
      IF X>0 THEN
         LET L$(X:X+T-1)="" !渡る

         IF MOD(P,2)=1 AND L$="" THEN !すべて渡り終えたなら ※奇数回かつφなら
            LET C=C+1
            PRINT "No.";C
            FOR J=1 TO P-1 !結果を表示する
               PRINT STR$(J);": ";
               IF MOD(J,2)=1 THEN
                  PRINT S$(B(J-1));"(";S$(A(J));")→"
               ELSE
                  PRINT "←(";S$(A(J));")";S$(B(J-1))
               END IF
            NEXT J
            PRINT STR$(P);": ";S$(i);"(";S$(i);")→"
            PRINT

         ELSE
            CALL checkRule(L$,D,S$, id) !安全に渡れるなら
            IF id>0 THEN

               LET R$=S$(D) !向こう側の岸の状態 ※補集合 ~L、差 U-L
               LET X=POS(R$,L$)
               LET R$(X:X+LEN(L$)-1)=""
               CALL checkRule(R$,D,S$, id) !安全に渡れるなら
               IF id>0 THEN

                  FOR J=P-2 TO 0 STEP -2 !同じ状態に戻っていないか
                     IF id=B(J) THEN EXIT FOR
                  NEXT J
                  IF J<0 THEN
                     LET A(P)=i !記録する
                     LET B(P)=id
                     CALL try(P+1,A,B, M,N,K, D,S$) !次へ
                     !!!IF P<5 THEN CALL try(P+1,A,B, M,N,K, D,S$) !次へ
                  END IF

               END IF

            END IF

         END IF

      END IF
   END IF
NEXT i
END SUB

EXTERNAL SUB checkRule(L$,D,S$(), id) !条件を満たすかどうか確認する
FOR id=1 TO D
   IF L$=S$(id) THEN EXIT SUB !パターン番号を返す
NEXT id
LET id=-1 !NG
END SUB



実行結果

No. 1
1: AAAaaa(aa)→
2: ←(a)aa
3: AAAaa(aa)→
4: ←(a)aaa
5: AAAa(AA)→
6: ←(Aa)AAaa
7: AAaa(AA)→
8: ←(a)AAAa
9: aaa(aa)→
10: ←(a)AAAaa
11: aa(aa)→

No. 2
1: AAAaaa(aa)→
2: ←(a)aa
3: AAAaa(aa)→
4: ←(a)aaa
5: AAAa(AA)→
6: ←(Aa)AAaa
7: AAaa(AA)→
8: ←(a)AAAa
9: aaa(aa)→
10: ←(A)AAAaa
11: Aa(Aa)→

No. 3
1: AAAaaa(Aa)→
2: ←(A)Aa
3: AAAaa(aa)→
4: ←(a)aaa
5: AAAa(AA)→
6: ←(Aa)AAaa
7: AAaa(AA)→
8: ←(a)AAAa
9: aaa(aa)→
10: ←(a)AAAaa
11: aa(aa)→

No. 4
1: AAAaaa(Aa)→
2: ←(A)Aa
3: AAAaa(aa)→
4: ←(a)aaa
5: AAAa(AA)→
6: ←(Aa)AAaa
7: AAaa(AA)→
8: ←(a)AAAa
9: aaa(aa)→
10: ←(A)AAAaa
11: Aa(Aa)→


 

戻る