問題解き              エクセルで遊ぼう 作画 製本 問題 作曲
川を渡るんだけど、キャベツ、羊、狼、狩人どうやって船に乗ったらいいのやら。他の問題もあります。
川渡り1 川渡り2  川渡り3 川渡り4  川渡り5

川渡り1

「キャベツ・羊・狼・狩人の川渡り」
船の定員は2名(キャベツや動物も1名と数えて)で、漕げるのは狩人だけ。
禁則:
・キャベツと羊だけがいっしょにいる
・狼と羊だけがいっしょにいる
・キャベツと羊と狼だけがいっしょにいる

計算方法は、2進法を用い、なし=0、キャベツ=1、羊=2、狼=4、狩人=8で計算すると、例えば合計10だったら羊と狩人だと分かる。
禁則のケースを避け、あと、計算の効率化のため船の移動の行き帰りで船のメンバーが同じケースを避けた。
A列をこちら岸、B列を船、C列を対岸として、それぞれメンバーの数値の合計で表現した。A列が0、C列が15になれば成功だ。
禁則をe(0〜2)、各メンバーがこちら岸にいる状態をh(0〜4)=trueで表すことにした(falseなら対岸にいる)。
川渡り

Option Explicit

Sub kawa1()
Dim i, j, k, x(4), e(2) As Integer
Dim h(4) As Boolean

Columns("a:c").ClearContents
x(0) = 0: x(1) = 1: x(2) = 2: x(3) = 4: x(4) = 8
e(0) = 3: e(1) = 6: e(2) = 7
For i = 0 To 4
h(i) = True
Next i
k = 1
Cells(k, 1) = 15
Cells(k, 3) = 0

'渡る
100 For i = 0 To 3
If (h(i) = False) Or (x(4) + x(i) = Cells(k, 2)) Then GoTo 500
For j = 0 To 2
If Cells(k, 1) - x(4) - x(i) = e(j) Then GoTo 500
Next j
k = k + 1
Cells(k, 2) = x(4) + x(i)
Cells(k, 1) = Cells(k - 1, 1) - Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) + Cells(k, 2)
h(4) = False
h(i) = False
h(0) = False
GoTo 600
500 Next i
Exit Sub

'判定
600 If Cells(k, 3) = 15 Then Exit Sub

'戻る
For i = 0 To 3
If (h(i) = True) Or (x(4) + x(i) = Cells(k, 2)) Then GoTo 700
For j = 0 To 2
If Cells(k, 3) - x(4) - x(i) = e(j) Then GoTo 700
Next j
k = k + 1
Cells(k, 2) = x(4) + x(i)
Cells(k, 1) = Cells(k - 1, 1) + Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) - Cells(k, 2)
h(4) = True
h(i) = True
h(0) = True
GoTo 100
700 Next i

End Sub

川渡り2

「8人家族の川渡り」
娘a・娘b・息子a・息子b・母・父・メイド・犬の家族。
船の定員は2名(犬も1名と数える)で、漕げるのは母と父とメイドだけ。
禁則:
・娘aまたは娘bが母のいないとき父といっしょにいる(けんかする?)
・息子aまたは息子bが父のいないとき母といっしょにいる(けんかする?)
・メイドのいないとき犬が誰かといる(噛まれる?)

計算方法は、またもや2進法を用い、なし=0、娘a=1、娘b=2、息子a=4、息子b=8、母=16、父=32、メイド=64、犬=128で計算すると、例えば合計18だったら母と娘bだと分かる。
禁則のケースを避け、あと、計算の効率化のため、いちばん最初はメイドと犬で渡り、船の移動の行き帰りで船のメンバーが同じケースを避けた。
A列をこちら岸、B列を船、C列を対岸として、それぞれメンバーの数値の合計で表現した。A列が0、C列が255になれば成功で、セルD1に「おめでとう」と表示する。
禁則をer、各メンバーがこちら岸にいる状態をh(0〜8)=trueで表すことにした(falseなら対岸にいる)。繰り返しの部分はサブルーチンにした。
川渡り2


Option Explicit

Sub kawa2()
Dim i, j, k, r, s, x(8), xx, ii, jj ,n As Integer
Dim h(8), er As Boolean
'0なし 1娘a 2娘b 3息子a 4息子b 5母 6父 7メイド 8犬
x(0) = 0: x(1) = 1: x(2) = 2: x(3) = 4: x(4) = 8
x(5) = 16: x(6) = 32: x(7) = 64: x(8) = 128

For n = 1 To 100
Columns("a:d").ClearContents
For i = 0 To 8
h(i) = True
Next i
k = 1
Cells(k, 1) = 255
Cells(k, 3) = 0

'渡る
100 r = Int(Rnd(1) * 3) + 5
If k = 1 Then r = 7
For i = r To r + 2
ii = i: If ii > 7 Then ii = ii - 3
s = Int(Rnd(1) * 9)
If k = 1 Then s = 8
For j = s To s + 8
jj = j: If jj > 8 Then jj = jj - 9
If (h(ii) = False) Or (h(jj) = False) Or (ii = jj) Then GoTo 500
If x(jj) + x(ii) = Cells(k, 2) Then GoTo 500
xx = Cells(k, 1) - x(ii) - x(jj)
GoSub 800: If er = True Then GoTo 500
xx = Cells(k, 3) + x(ii) + x(jj)
GoSub 800: If er = True Then GoTo 500
xx = x(ii) + x(jj)
If (xx = 33) Or (xx = 34) Or (xx = 20) Or (xx = 24) Or (xx = 144) Or (xx = 160) Then GoTo 500
k = k + 1
Cells(k, 2) = x(ii) + x(jj)
Cells(k, 1) = Cells(k - 1, 1) - Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) + Cells(k, 2)
h(ii) = False
h(jj) = False
h(0) = False
GoTo 600
500 Next j
Next i
GoTo 750
Exit Sub

'判定
600 If Cells(k, 3) = 255 Then
Cells(1, 4) = n & "おめでとう"
Exit Sub
End If

'戻る
r = Int(Rnd(1) * 3) + 5
For i = r To r + 2
ii = i: If ii > 7 Then ii = ii - 3
s = Int(Rnd(1) * 9)
For j = s To s + 8
jj = j: If jj > 8 Then jj = jj - 9
If (h(ii) = True) Or (h(jj) = True) Or (ii = jj) Then GoTo 700
If x(jj) + x(ii) = Cells(k, 2) Then GoTo 700
xx = Cells(k, 1) + x(ii) + x(jj)
GoSub 800: If er = True Then GoTo 700
xx = Cells(k, 3) - x(ii) - x(jj)
GoSub 800: If er = True Then GoTo 700
xx = x(ii) + x(jj)
If (xx = 33) Or (xx = 34) Or (xx = 20) Or (xx = 24) Or (xx = 144) Or (xx = 160) Then GoTo 700
k = k + 1
Cells(k, 2) = x(ii) + x(jj)
Cells(k, 1) = Cells(k - 1, 1) + Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) - Cells(k, 2)
h(ii) = True
h(jj) = True
h(0) = True
GoTo 100
700 Next j
Next i
750 Next n
Exit Sub

800 If ((xx And x(1)) = x(1)) And ((xx And x(5)) = 0) And ((xx And x(6)) = x(6)) Then
er = True
ElseIf ((xx And x(2)) = x(2)) And ((xx And x(5)) = 0) And ((xx And x(6)) = x(6)) Then
er = True
ElseIf ((xx And x(3)) = x(3)) And ((xx And x(5)) = x(5)) And ((xx And x(6)) = 0) Then
er = True
ElseIf ((xx And x(4)) = x(4)) And ((xx And x(5)) = x(5)) And ((xx And x(6)) = 0) Then
er = True
ElseIf ((xx And x(7)) = 0) And (xx > x(8)) Then
er = True
Else
er = False
End If

Return

End Sub
なお、計算する組み合わせが多く、なかなか解けないため、コマンドボタンを1回押すと100回実行するように改良した(解ければ即終了、おめでとうの前に回数を表示)。

川渡り3

「ウサギ3匹、犬3匹の川渡り」
船の定員は2名(動物だが1名と数える)で、全員漕げる。
禁則:
ウサギが犬の数より少ない状態(噛まれる?)

計算方法は、またもや2進法を用い、なし=0、ウサギa=1、ウサギb=2、ウサギc=4、犬a=8、犬b=16、犬c=32で計算すると、例えば合計12だったら犬aとウサギcだと分かる。
禁則のケースを避け、あと、計算の効率化のため船の移動の行き帰りで船のメンバー(動物の種類)が同じケースを避けた。
A列をこちら岸、B列を船、C列を対岸として、それぞれメンバーの数値の合計で表現した。D列には船に乗った動物の種類が簡単に分かる値を入れた(ウサギを1、犬を3とした合計。合計2ならウサギ2匹、合計4ならウサギと犬だと分かる)。
A列が0、C列が63になれば成功で、セルD1に「おめでとう」と表示する。
禁則をe(0〜14)、各メンバーがこちら岸にいる状態をh(0〜6)=trueで表すことにした(falseなら対岸にいる)。
ウサギ3匹と犬3匹の川渡り問題


Option Explicit

Sub kawa3()
Dim i, j, k, m, n, x(6), y(6), rr, ss, ii, jj, e(14) As Integer
Dim h(6) As Boolean

Columns("a:d").ClearContents
x(0) = 0: x(1) = 1: x(2) = 2: x(3) = 4: x(4) = 8: x(5) = 16: x(6) = 32
y(0) = 0: y(1) = 1: y(2) = 1: y(3) = 1: y(4) = 3: y(5) = 3: y(6) = 3
e(0) = 57: e(1) = 58: e(2) = 60: e(3) = 59: e(4) = 61
e(5) = 62: e(6) = 25: e(7) = 26: e(8) = 28: e(9) = 41
e(10) = 42: e(11) = 44: e(12) = 49: e(13) = 50: e(14) = 52

For i = 0 To 6
h(i) = True
Next

k = 1
Cells(k, 1) = 63
Cells(k, 3) = 0

'渡る
100 rr = Int(Rnd(1) * 6) + 1
For i = rr To rr + 5
ii = i: If ii > 6 Then ii = ii - 6
If h(ii) = True Then
ss = Int(Rnd(1) * 7)
For j = ss To ss + 6
jj = j: If jj > 6 Then jj = jj - 7
If (h(jj) = False) Or (y(ii) + y(jj) = Cells(k, 4)) Or (ii = jj) Then GoTo 500
For n = 0 To 14
If Cells(k, 1) - x(ii) - x(jj) = e(n) Then GoTo 500
If Cells(k, 3) + x(ii) + x(jj) = e(n) Then GoTo 500
Next n
k = k + 1
Cells(k, 2) = x(ii) + x(jj)
Cells(k, 1) = Cells(k - 1, 1) - Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) + Cells(k, 2)
Cells(k, 4) = y(ii) + y(jj)
h(ii) = False
h(jj) = False
h(0) = False
GoTo 600
500 Next j
End If
Next i
Exit Sub

'判定
600 If Cells(k, 3) = 63 Then
Cells(1, 4) = "おめでとう"
Exit Sub
End If

'戻る
rr = Int(Rnd(1) * 6) + 1
For i = rr To rr + 5
ii = i: If ii > 6 Then ii = ii - 6
If h(ii) = False Then
ss = Int(Rnd(1) * 7)
For j = ss To ss + 6
jj = j: If jj > 6 Then jj = jj - 7
If (h(jj) = True) Or (y(ii) + y(jj) = Cells(k, 4)) Or (ii = jj) Then GoTo 700
For n = 0 To 14
If Cells(k, 3) - x(ii) - x(jj) = e(n) Then GoTo 700
If Cells(k, 1) + x(ii) + x(jj) = e(n) Then GoTo 700
Next n

k = k + 1
Cells(k, 2) = x(ii) + x(jj)
Cells(k, 1) = Cells(k - 1, 1) + Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) - Cells(k, 2)
Cells(k, 4) = y(ii) + y(jj)
h(ii) = True
h(jj) = True
h(0) = True

GoTo 100
700 Next j
End If
Next i

End Sub

川渡り4

「夫婦3組の川渡り」
船の定員は2名で、全員漕げる。
禁則:
妻は夫がいないときに他の夫といっしょにいるのはダメ(やきもち?)。

計算方法は、2進法を用い、なし=0、妻a=1、妻b=2、妻c=4、夫a=8、夫b=16、夫c=32で計算すると、例えば合計36だったら妻cと夫cだと分かる。夫a妻a、夫b妻b、夫c妻cは夫婦だ。
禁則のケースを避け、あと、計算の効率化のため船の移動の行き帰りで船のメンバーが同じケースを避けた。
A列をこちら岸、B列を船、C列を対岸として、それぞれメンバーの数値の合計で表現した。
A列が0、C列が63になれば成功で、セルD1に「おめでとう」と表示する。
禁則をer、各メンバーがこちら岸にいる状態をh(0〜6)=trueで表すことにした(falseなら対岸にいる)。
夫婦3組の川渡り問題


Option Explicit

Sub kawa4()
Dim i, j, k, n, x(6), rr, ss, ii, jj, z1, z2, z3 As Integer
Dim h(6), er As Boolean

Columns("a:d").ClearContents
x(0) = 0: x(1) = 1: x(2) = 2: x(3) = 4: x(4) = 8: x(5) = 16: x(6) = 32

For i = 0 To 6
h(i) = True
Next

k = 1
Cells(k, 1) = 63
Cells(k, 3) = 0

'渡る
100 rr = Int(Rnd(1) * 6) + 1
For i = rr To rr + 5
ii = i: If ii > 6 Then ii = ii - 6
If h(ii) = True Then
ss = Int(Rnd(1) * 7)
For j = ss To ss + 6
jj = j: If jj > 6 Then jj = jj - 7
If (h(jj) = False) Or (x(ii) + x(jj) = Cells(k, 2)) Or (ii = jj) Then GoTo 500
GoSub 900: If er = True Then GoTo 500
k = k + 1
Cells(k, 2) = x(ii) + x(jj)
Cells(k, 1) = Cells(k - 1, 1) - Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) + Cells(k, 2)

h(ii) = False
h(jj) = False
h(0) = False
GoTo 600
500 Next j
End If
Next i
Exit Sub

'判定
600 If Cells(k, 3) = 63 Then
Cells(1, 4) = "おめでとう"
Exit Sub
End If

'戻る
rr = Int(Rnd(1) * 6) + 1
For i = rr To rr + 5
ii = i: If ii > 6 Then ii = ii - 6
If h(ii) = False Then
ss = Int(Rnd(1) * 7)
For j = ss To ss + 6
jj = j: If jj > 6 Then jj = jj - 7
If (h(jj) = True) Or (x(ii) + x(jj) = Cells(k, 2)) Or (ii = jj) Then GoTo 700
GoSub 900: If er = True Then GoTo 700
k = k + 1
Cells(k, 2) = x(ii) + x(jj)
Cells(k, 1) = Cells(k - 1, 1) + Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) - Cells(k, 2)

h(ii) = True
h(jj) = True
h(0) = True
GoTo 100
700 Next j
End If
Next i
Exit Sub

900 z1 = x(ii) + x(jj)
z2 = Cells(k, 1) - z1
z3 = Cells(k, 3) + z1
If (z1 = 17) Or (z1 = 33) Or (z1 = 10) Or (z1 = 34) Or (z1 = 12) Or (z1 = 20) Then
er = True
ElseIf ((z2 And x(1)) = x(1)) And ((z2 And x(4)) = 0) And (((z2 And x(5)) = x(5)) Or ((z2 And x(6)) = x(6))) Then
er = True
ElseIf ((z2 And x(2)) = x(2)) And ((z2 And x(5)) = 0) And (((z2 And x(4)) = x(4)) Or ((z2 And x(6)) = x(6))) Then
er = True
ElseIf ((z2 And x(3)) = x(3)) And ((z2 And x(6)) = 0) And (((z2 And x(4)) = x(4)) Or ((z2 And x(5)) = x(5))) Then
er = True
ElseIf ((z3 And x(1)) = x(1)) And ((z3 And x(4)) = 0) And (((z3 And x(5)) = x(5)) Or ((z3 And x(6)) = x(6))) Then
er = True
ElseIf ((z3 And x(2)) = x(2)) And ((z3 And x(5)) = 0) And (((z3 And x(4)) = x(4)) Or ((z3 And x(6)) = x(6))) Then
er = True
ElseIf ((z3 And x(3)) = x(3)) And ((z3 And x(6)) = 0) And (((z3 And x(4)) = x(4)) Or ((z3 And x(5)) = x(5))) Then
er = True
Else
er = False
End If
Return
End Sub

川渡り5

「10人家族の川渡り」
犬も一人と数えて娘a、娘b、息子a、息子b、母、父、メイド、爺、赤ちゃん、犬の10人家族。
船の定員は2名で、大人だけ漕げる。
禁則
・母がいないときに父と娘をいっしょにいさせる(けんかする?)
・父がいないときに母と息子をいっしょにいさせる(けんかする?)
・親がいないときに爺と「娘または息子または赤ちゃん」をいっしょにいさせる(けんかする?)
・親がいないときに「娘または息子」と赤ちゃんをいっしょにいさせる(けんかする?)
・メイドがいないときに犬とだれかとをいっしょにいさせる(噛まれる?)

計算方法は、2進法を用い、なし=0、娘a=1、娘b=2、息子a=4、息子b=8、母=16、父=32、メイド=64、爺=128、赤ちゃん=256、犬=512で計算すると、例えば合計578だったらメイドと犬だと分かる。

禁則のケースを避け、あと、計算の効率化のため、下記のようにした。
・いちばん最初は、メイドと犬で渡る。
・船の移動の行き帰りで船のメンバーが同じケースを避ける。
・子ども(娘・息子・赤ちゃん)を帰りの船に乗せない。
・こちら岸に子ども一人だけになったらメイドと犬で迎えに来る。
・こちら岸に犬だけになったらメイドだけで迎えに来る。
・こちら岸の状態(ボートの位置を含む)が以前と同じになるのはなるべく避ける。

A列をこちら岸、B列を船、C列を対岸として、それぞれメンバーの数値の合計で表現した。
A列が0、C列が1023になれば成功で、セルD1に「おめでとう」と表示する。
禁則をer、各メンバーがこちら岸にいる状態をh(0〜10)=trueで表すことにした(falseなら対岸にいる)。
なお、計算する組み合わせが多く、なかなか解けないため、コマンドボタンを1回押すと100回実行するようにした(解ければ即終了、おめでとうの前に回数を表示)。
10人家族の川渡り問題


Option Explicit

Sub kawa5()
Dim i, j, k, r, s, x(10), xx, ii, jj, m, n As Integer
Dim h(10), er As Boolean

x(0) = 0: x(1) = 1: x(2) = 2: x(3) = 4: x(4) = 8
x(5) = 16: x(6) = 32: x(7) = 64: x(8) = 128: x(9) = 256: x(10) = 512

For n = 1 To 100

Columns("a:d").ClearContents
For i = 0 To 10
h(i) = True
Next i
k = 1
Cells(k, 1) = 1023
Cells(k, 3) = 0

'渡る
100 r = Int(Rnd(1) * 4) + 5
For i = r To r + 3
ii = i: If ii > 8 Then ii = ii - 4
s = Int(Rnd(1) * 11)
For j = s To s + 10
jj = j: If jj > 10 Then jj = jj - 11
If k = 1 Then
ii = 7: jj = 10
GoTo 450
End If

If (h(ii) = False) Or (h(jj) = False) Or (ii = jj) Then GoTo 500
If x(jj) + x(ii) = Cells(k, 2) Then GoTo 500
GoSub 900: If er = True Then GoTo 500
xx = Cells(k, 1) - x(ii) - x(jj)
GoSub 800: If er = True Then GoTo 500
xx = Cells(k, 3) + x(ii) + x(jj)
GoSub 800: If er = True Then GoTo 500
xx = x(ii) + x(jj)

If (xx = 33) Or (xx = 34) Or (xx = 20) Or (xx = 24) Or (xx = 528) Or (xx = 544) Or (xx = 640) _
Or (xx = 129) Or (xx = 130) Or (xx = 132) Or (xx = 136) Or (xx = 384) Then GoTo 500
450 k = k + 1
Cells(k, 2) = x(ii) + x(jj)
Cells(k, 1) = Cells(k - 1, 1) - Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) + Cells(k, 2)
h(ii) = False
h(jj) = False
h(0) = False
GoTo 600
500 Next j
Next i
GoTo 750

'判定
600 If Cells(k, 3) = 1023 Then
Cells(1, 4) = n & "おめでとう"
Exit Sub
End If

'戻る
r = Int(Rnd(1) * 4) + 5
For i = r To r + 3
ii = i: If ii > 8 Then ii = ii - 4
s = Int(Rnd(1) * 11)
For j = s To s + 10
jj = j: If jj > 10 Then jj = jj - 11
If (h(ii) = True) Or (h(jj) = True) Or (ii = jj) Then GoTo 700
If (Cells(k, 1) = 1) Or (Cells(k, 1) = 2) Or (Cells(k, 1) = 4) Or (Cells(k, 1) = 8) Or (Cells(k, 1) = 256) Then
ii = 7: jj = 10
GoTo 650
ElseIf Cells(k, 1) = 512 Then
ii = 7: jj = 0
GoTo 650
End If
If (jj = 1) Or (jj = 2) Or (jj = 3) Or (jj = 4) Or (jj = 9) Then GoTo 700
If x(jj) + x(ii) = Cells(k, 2) Then GoTo 700

GoSub 950: If er = True Then GoTo 700
xx = Cells(k, 1) + x(ii) + x(jj)
GoSub 800: If er = True Then GoTo 700
xx = Cells(k, 3) - x(ii) - x(jj)
GoSub 800: If er = True Then GoTo 700
xx = x(ii) + x(jj)

650 k = k + 1
Cells(k, 2) = x(ii) + x(jj)
Cells(k, 1) = Cells(k - 1, 1) + Cells(k, 2)
Cells(k, 3) = Cells(k - 1, 3) - Cells(k, 2)
h(ii) = True
h(jj) = True
h(0) = True
GoTo 100
700 Next j
Next i

750 Next n
Exit Sub

800 If (((xx And x(1)) = x(1)) Or ((xx And x(2)) = x(2))) And ((xx And x(5)) = 0) And ((xx And x(6)) = x(6)) Then
er = True
ElseIf (((xx And x(3)) = x(3)) Or ((xx And x(4)) = x(4))) And ((xx And x(5)) = x(5)) And ((xx And x(6)) = 0) Then
er = True
ElseIf ((xx And x(8)) = x(8)) And ((xx And x(5)) = 0) And ((xx And x(6)) = 0) And _
(((xx And x(1)) = x(1)) Or ((xx And x(2)) = x(2)) Or ((xx And x(3)) = x(3)) Or ((xx And x(4)) = x(4)) Or ((xx And x(9)) = x(9))) Then
er = True
ElseIf ((xx And x(5)) = 0) And ((xx And x(6)) = 0) And ((xx And x(9)) = x(9)) And _
(((xx And x(1)) = x(1)) Or ((xx And x(2)) = x(2)) Or ((xx And x(3)) = x(3)) Or ((xx And x(4)) = x(4))) Then
er = True
ElseIf ((xx And x(7)) = 0) And (xx > x(10)) Then
er = True
Else
er = False
End If

Return
900 For m = 1 To k Step 2
If (Cells(m, 3) = Cells(k, 3) + x(ii) + x(jj)) And (Rnd(1) > 0.9) Then
er = True
Return
Else
er = False
End If
Next m
Return

950 For m = 2 To k Step 2
If (Cells(m, 1) = Cells(k, 1) + x(ii) + x(jj)) And (Rnd(1) > 0.9) Then
er = True
Return
Else
er = False
End If
Next m
Return

End Sub
Copyright ©2000 Moritoizumi all rights reserved.
もどる このページの先頭へ inserted by FC2 system