ヘルゴルフ

ヘルゴルフ
http://www.nikoli.co.jp/ja/puzzles/herugolf.html
解答
例題 (ニコリのパズル紹介より)
4
4
H
H
H
H
H
2
2
2
H
2
ルール
以下の条件に従って○(ボール)をH(ホール)のマスまで移動する。
①すべてのHのマスにボールが一つづつ運ばれる。
②各回の○の移動は矢印で表す。矢印の線が他の丸やHのマスを通過したり、線どうしが
交差したり重なってはいけない。
③1回の移動で、○はタテかヨコにまっすぐ、丸の中の数字の分だけマスを動く。
1回の移動が終わると丸の数字は1減り、また移動することがでる。移動の方向は変わってもよい。
数字が0になったボールや、Hのマスに停止したボールはそれ以上移動できない。
④○が盤面の外に出たり(OB)、灰色のマス(池)で停止したりするような移動はできない。
ボール1
ボール2
変数
マスの行番号をI、列番号をJとし、与えられた○にも番号を振っておく。
C(I,J,K) = 1
= 0
マス(I,J)にK番目のボールが通るとき
〃 通らないとき
マス(I,J)がホールのとき
〃 でないとき
H(I,J) = 1
= 0
I 1
↓ 2
J →
1 2
4
3
.
.
.
Nr
sL(K,L) = 1
K番目のボールのLストローク目が左方向のとき
〃 でないとき
= 0
sR(K,L) = 1
K番目のボールのLストローク目が右方向のとき
〃 でないとき
= 0
sU(K,L) = 1
K番目のボールのLストローク目が上方向のとき
〃 でないとき
= 0
sD(K,L) = 1
K番目のボールのLストローク目が下方向のとき
〃 でないとき
= 0
S(I,J,K,L) = 1 マス(I,J)がK番目のボールのLストローク目の終点のとき
= 0
〃 でないとき
目的関数
minimize
x
(ダミー)
制約式
subject to
1.ホール位置設定
H (I,J)=1 または H(I,J)=0
(I,Jは盤面読み取り)
H
2
3
4
. . .
Nc
2.マスを通過するボールはどれか1個以下だから
Nb
C (I,J,K)≦ 1
Σ
K=1
(I=1,2,....Nr) Nbはボールの総数
(J=1,2,....Nc)
ただし初期ボールのあるマスではC(I,J,K)=1、C(I,J,KK)=0 (KKはK以外のとき)
3.ボールの飛ぶ方向は1方向だから
sL(K,L)+sD(K,L)+sR(K,L)+sU(K,L)≦ 1
(K=1,2,....Nb)
(L=0,1,....Ns(K)-1)
Ns(K)はボールのストローク数
(盤面丸の中の数値)
4.最初のストロークは必ずある
sL(K,0)+sD(K,0)+sR(K,0)+sU(K,0)≧ 1
5.S(I,J,K,L)の初期値S(I,J,K,0)をセット
初期ボール位置に対し
S(I,J,K,0)=1
S(I,J,K,L)=0
(L=1,....Ns(K))
(K=1,2,....Nb)
(I,Jは初期ボール位置)
初期ボール位置以外ではストローク違いが同一マスには来ないから
S(I,J,K,L)+S(I,J,K,LL)≦ 1 (K=1,2,....Nb)
(I=1,2,....Nr)
(LL>L)
(I,Jは初期ボール位置以外)
(J=1,2,....Nc)
6.マス(I,J)には(K,L)の異なるボールがくるから
Nr
Nc
(K=1,2,....Nb)
(L=0,1,....Ns(K))
Σ
Σ S(I,J,K,L)≦ 1
I=1 J=1
7.ボールが盤から飛び出さないための方向制限
sL(K,L)+S(I,J,K,L)≦
sR(K,L)+S(I,J,K,L)≦
sU(K,L)+S(I,J,K,L)≦
sD(K,L)+S(I,J,K,L)≦
1
1
1
1
(J≦Ns(K)-L)
(J>Nc-(Ns(K)-L))
(I≦Ns(K)-L)
(I>Nr-(Ns(K)-L))
(K=1,2,....Nb)
(L=0,1,....Ns(K))
(I=1,2,....Nr)
(J=1,2,....Nc)
7.S(I,J,K,L)は池には来ない
(K=1,2,....Nb)
S(I,J,K,L)=0
(L=0,1,....Ns(K))
(I,Jは全ての池のマス)
8.マス(I,J)がホールならば、S(I,J,K,L)のどれかが来る
Nb
Ns(K)
Σ
Σ S(I,J,K,L)≧ 1
K=1 L=1
(I,Jは全てのホールマス)
9.S(I,J,K,L)=1でマス(I,J)がホールでなければストローク矢印が付く
S(I,J,K,L)-{H(I,J)+sL(K,L)+sD(K,L)+sR(K,L)+SU(K,L)}≦ 0
(K=1,2,....Nb)
(L=1,2,....Ns(K)-1)
(I=1,2,....Nr)
(J=1,2,....Nc)
10.S(I,J,K,L)=1でマス(I,J)がホールならばLより先のストローク矢印はない
S(I,J,K,L)+{sL(K,LL)+sD(K,LL)+sR(K,LL)+SU(K,LL)}≦ 1
(LL>L)
(K=1,2,....Nb)
(L=1,2,....Ns(K)-1)
(I,Jは全てのホールマス)
11.ストローク矢印がなければ S(I,J,K,L)=0
S(I,J,K,L)-{sL(K,LL)+sD(K,LL)+sR(K,LL)+SU(K,LL)}≦ 0
(LL=L-1)
(K=1,2,....Nb)
(L=1,2,....Ns(K))
(I=1,2,....Nr)
(J=1,2,....Nc)
12.ストローク矢印の逆戻り禁止
sL(K,L)+sR(K,L+1)≦
sR(K,L)+sL(K,L+1)≦
sU(K,L)+sD(K,L+1)≦
sD(K,L)+sU(K,L+1)≦
1
1
1
1
(K=1,2,....Nb)
(L=0,1,....Ns(K)-1)
13.ストロークによる S(I,J,K,L)位置の移動
S(I,J,K,L)=1 で sL(K,L)=1 のとき S(I,JJ,K,L+1)=1であるから
ただし JJ=J-(Ns(K)-L) :Lストローク目のマス移動
sL(K,L)+S(I,J,K,L)-S(I,JJ,K,L+1)≦ 1
また移動途中のマスはK番ボールの通過マスになるから
sL(K,L)+S(I,J,K,L)-C(I,JJJ,K)≦ 1
ただし JJJ=J-1∼J-(Ns(K)-L)
同様にして
sR(K,L)+S(I,J,K,L)-S(I,JJ,K,L+1)≦ 1
JJ=J+(Ns(K)-L)
sR(K,L)+S(I,J,K,L)-C(I,JJJ,K)≦ 1
JJJ=J+1∼J+(Ns(K)-L)
sU(K,L)+S(I,J,K,L)-S(II,J,K,L+1)≦ 1
II=I-(Ns(K)-L)
sU(K,L)+S(I,J,K,L)-C(III,J,K)≦ 1
III=I-1∼I-(Ns(K)-L)
sD(K,L)+S(I,J,K,L)-S(II,J,K,L+1)≦ 1
II=I+(Ns(K)-L)
sD(K,L)+S(I,J,K,L)-C(III,J,K)≦ 1
III=I+1∼I+(Ns(K)-L)
上下界
bounds
変数型
binary
H(I,J)
(I=1,2….…Nr)
(J=1,2….…Nc)
C(I,J,K)
(K=1,2….…Nb)
(I=1,2….…Nr)
(J=1,2….…Nc)
sL(K,L) sR(K,L) sU(K,L) sD(K,L)
S(I,J,K,L)
(K=1,2….…Nb)
(L=0,1….…Ns(K))
(I=1,2….…Nr)
(J=1,2….…Nc)
(K=1,2….…Nb)
(L=0,1….…Ns(K))
終端
end
整数計画法 scip の read solution ファイルから、sL,sR,sU,sDを読んで解とする。
C(I,J,K)はボールが通過しなかったマスに、不定のボール番号が付いて見難い。
solution ファイルを読んでExcel Sheetに矢印を描くVBAプログラムリストを次ページに添付する。
ただし、これまでの説明では、配列の変数名がsL(3,2)などとなっているが、実際のプログラムでは
sL3_2として出力されている。
Private Sub CommandButton3_Click()
Dim TextLine As String
Dim I As Integer, J As Integer, K As Integer, L1 As Integer
Dim Nr As Integer, Nc As Integer, Length As Integer
Dim Crow As Integer, Ccol As Integer, Cgrp As Integer
Dim Ret As Variant, lastLine As Integer, lastCol As Integer
Dim Nball As Integer, BallHit(20) As Integer
Dim Dij(20, 20) As String * 1, BallI(20) As Integer, BallJ(20) As Integer
Dim Ar As String * 1, Ball As Integer, Stroke As Integer
Dim ScX As Integer, ScY As Integer, X0 As Integer, Y0 As Integer
'
ChDrive Left(Application.ThisWorkbook.Path, 1)
ChDir Application.ThisWorkbook.Path
'
ScX = 27.2
エクセルシートの列幅、行高さに合わせ調節しないとずれる。
ScY = 27.2
'
' find Input Range
For I = 1 To 20
If Cells(I, 1).Borders(xlEdgeBottom).LineStyle = 1 Then
Nr = I
End If
Next I
'
For J = 1 To 20
If Cells(1, J).Borders(xlEdgeBottom).LineStyle = 1 Then
Nc = J
End If
Next J
Debug.Print "Nr=", Nr
Debug.Print "Nc=", Nc
'
' Read Ball position
Nball = 0
For I = 1 To Nr
For J = 1 To Nc
If IsNumeric(Cells(I, J)) = False Then
ElseIf IsEmpty(Cells(I, J)) = False Then
Nball = Nball + 1
BallI(Nball) = I
BallJ(Nball) = J
BallHit(Nball) = Cells(I, J).Value
Dij(I, J) = "B"
End If
Next J
Next I
Open "HellGolf.sol" For Input As #2
Do While Not EOF(2)
Line Input #2, TextLine
If Left(TextLine, 8) = "solution" Then GoTo L2
If Left(TextLine, 1) = "s" Then
Length = InStr(TextLine, " ") - 1
'
L1 = InStr(TextLine, "_")
Ar = Mid(TextLine, 2, 1)
Ball = Val(Mid(TextLine, 3, L1 - 3))
Stroke = Val(Mid(TextLine, L1 + 1, Length - L1))
If Stroke = 0 Then
X0 = BallJ(Ball)
Y0 = BallI(Ball)
End If
If Ar = "L" Then
J = X0 - (BallHit(Ball) - Stroke)
I = Y0
ElseIf Ar = "D" Then
J = X0
I = Y0 + (BallHit(Ball) - Stroke)
ElseIf Ar = "R" Then
J = X0 + (BallHit(Ball) - Stroke)
I = Y0
ElseIf Ar = "U" Then
J = X0
I = Y0 - (BallHit(Ball) - Stroke)
End If
ActiveSheet.Shapes.AddLine(ScX / 2 + (X0 - 1) * ScX, ScY / 2 + (Y0 - 1) * ScY, _
ScX / 2 + (J - 1) * ScX, ScY / 2 + (I - 1) * ScY).Select
Selection.ShapeRange.Line.EndArrowheadStyle = msoArrowheadTriangle
Selection.ShapeRange.Line.EndArrowheadLength = msoArrowheadLengthMedium
Selection.ShapeRange.Line.EndArrowheadWidth = msoArrowheadWidthMedium
X0 = J
Y0 = I
End If
L2:
Loop
Close #2
'
'
End Sub