次のパズルでは、次のような方法でグリッドを青と白の正方形で埋めようとします。
白を0で、青を1で表すと、次のようになります。
0 _ _ _ 1 _
_ 0 _ _ _ _
_ _ _ _ _ 0
1 _ _ 0 _ _
_ _ 1 1 _ _
_ 0 _ _ 1 _
そして、私たちはそれをかなり迅速に確認することができます
0 1 0 0 1 1
0 0 1 1 0 1
1 1 0 1 0 0
1 1 0 0 1 0
0 0 1 1 0 1
1 0 1 0 1 0
この例の解決策です。
制約として、私は次のように書きました。
constraints(Board,N) :-
N2 is N // 2,
( for(I,1,N), param(Board,N2,N)
do
Row is Board[I,1..N],
Col is Board[1..N,I],
ic_global:sequence_total(N2,N2,1,2,3,Row),
ic_global:sequence_total(N2,N2,1,2,3,Col)
).
sequence_total / 6は、値1が行/列で正確にN2回(Nの半分の時間)発生し、3要素の指定された行/列のすべてのシーケンスが1の値の1〜2倍を含むことを保証します(したがって、値が1の3つの正方形が隣り合って表示されることはありません)。
18x18パズルインスタンス(*)で次の結果が得られます。
Solved in 147 backtracks
Yes (10.39s cpu, solution 1)
'147のバックトラックのみが必要であるため、検索が実行される前に、制約が非常にうまく機能しているように見えます。ただし、特にバックトラックの量と比較すると、実行時間は非常に長いように思えます。これは、発生しなければならないすべてのシーケンスチェックによるものだと思いますか?search / 6の選択/選択方法のいずれかを変更しても、実行時間にほとんど影響がないという事実は、それを確認しているようです。
もしそうなら、リスト/配列内のシーケンスを制約して、N個の同一の要素が隣り合っていないようにし、実行時間を改善する他のより効率的な方法はありますか?
編集
以下の@jschimpfによって提供される分解バージョンを使用した後、次の結果が得られます。
Solved in 310 backtracks
Yes (0.22s cpu, solution 1)
新しい制約はsequence / 6ほど強力ではなく、もう少しバックトラックが必要ですが、実行時間は10.39秒から0.22秒に短縮されたため、全体的な結果は非常に望ましいものです。
サンプルデータ:
この質問に使用されるパズル(バックトラックなしで解決)
問題(p(6,1)、[(1,1,0)、(1,5,1)、(2,2,0)、(3,6,0)、(4,1,1)、 (4,4,0)、(5,3,1)、(5,4,1)、(6,2,0)、(6,5,1)])。
結果を投稿したパズル(*):
問題(p(18,1)、[(1,3,0)、(1,9,0)、(1,10,0)、(1,12,0)、(1,14,0)、 (1,18,1)、(2,4,0)、(2,7,1)、(2,8,1)、(3,2,1)、(3,6,0)、(3 、16,0)、(3,17,0)、(4,2,1)、(4,4,1)、(4,10,1)、(4,13,1)、(4,18 、1)、(5,8,1)、(5,10,1)、(5,15,0)、(5,16,1)、(6,12,1)、(7,3,0 )、(7,4,0)、(7,6,1)、(7,9,0)、(7,12,1)、(7,17,0)、(8,1,1)、 (8,4,0)、(8,8,1)、(8,15,1)、(8,16,1)、(9,7,0)、(9,10,0)、(9 、14,0)、(10,2,1)、(10,4,1)、(10,6,1)、(10,13,1)、(11,7,0)、(11,10 、1)、(12,1,1)、(12,4,1)、(12,7,1)、(12,15,1)、(12,16,1)、(13,1,1 )、(13,6,0)、(13,8,1)、(13,10,0)、(13,16,1)、(14,5,1)、(14,10,0)、 (14,13,1)、(15,1,1)、(15,3,1)、(15,12,0)、(15,13,1)、(15,15,0)、(16 、2,1)、(16,4,0)、(16,12,0)、(16,18,0)、(17,9,0)、(17,15,0)、(17,18 、0)、(18,2,1)、(18,8,1)、(18,11,1)、(18,15,1)、(18,16,1)])。
この場合、シーケンス制約の手作りの分解バージョンの方がはるかに効率的であることがわかります。たとえば、
sequence_1_2([X1,X2,X3|Xs]) :- !,
S #:: 1..2,
X1+X2+X3 #= S,
sequence_1_2([X2,X3|Xs]).
sequence_1_2(_).
これは、3要素のサブシーケンスの合計を1または2に制約し、sequence_total / 6制約を次のように置き換えます。
...,
sum(Row) #= N2,
sequence_1_2(Row),
これにより、解決時間が0.2秒に短縮されます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加