現在の閲覧者数:

N-Queens 超高速

前の版(高速)より速くなりました。ユニーク解が求まります。

♪ プログラムコード code

% nqueens_fast_more.pl

%---------------------------------------------------------------------------%
main :-
	set_gvar(count, 0),		% グローバル変数カウンタリセット
	write( 'N Queens!!\n' ),	% パズル名
	write( 'N = ' ),		% N =     N_Queens
	flush_output,			% 表示を反映する
	read( N ),			% N を読み込む
	statistics(runtime, _),		% 時間測定リセット
	solution( N, Q ),		% N_Queens を求める
	x/y( Q, Q1, 1 ),		% [Y1,Y2,...]形式から[1/Y1,2/Y2,...]へ変換 
	min_size( Q1, N ),		% 対称性:左上から下へ早く Q に出会った? 
	write( Q ),			% ユニーク解を表示
	gvar(count, CNT),		% グローバル変数カウンタ値取得 
	write( ' ' ),			% 空白を表示
	write( CNT ),			% 解の番号を表示
	flush_output,			% 表示を反映する
	nl,				% 改行
	fail.				% 失敗駆動:別解を求める

%---------------------------------------------------------------------------%
main :-
	statistics(runtime, [_,T]),	% 時間測定計時
	write('CPU time = '),		% 
	write(T),			% 
	write(' msec'),			% 
	nl,				% 
	!,				% 
	fail.				% 
%---------------------------------------------------------------------------%



solution( N, Q ) :-
	range( 1, N, R ),
	solution( R, [], Q ).

solution( [], Q, Q ) :- !.
solution( R, Q, Ans ) :-
	select( A, R, R1 ),
	noattack( A, Q, 1 ),
	solution( R1, [A|Q], Ans ).

range( M, M, [M] ):- M > 0, !.
range( N, M, [N|R] ) :-
    N > 0,
    N1 is N + 1,
    range( N1, M, R ).

noattack( _, [], _ ).
noattack( Y, [Y1|Ylist], Xdist ) :-
	Y1 - Y  =\= Xdist,
	Y  - Y1 =\= Xdist,
	Dist1 is Xdist + 1,
	noattack( Y, Ylist, Dist1 ).
	
%---------------------------------------------------------------------------%

% グローバル変数エンジン gvar(Name, X)がグローバル変数

set_gvar(Name, X) :-
    nonvar(Name), retract(gvar(Name, _)), !, asserta(gvar(Name, X)).
set_gvar(Name, X) :-
    nonvar(Name), asserta(gvar(Name, X)).

%---------------------------------------------------------------------------%

% -- 求まった解から上下左右反転解を求め -- %
% -- 大小関係を定義してより小さければ成功する -- %

% min_size( Queens ):  左右上下反転の同一解の内、最小解なら成功する。

min_size( Queens, N ) :-
	change_90( Queens, Queens90, N ),
	ck_min( Queens, Queens90 ),
	change_90( Queens90, Queens180, N ),
	ck_min( Queens, Queens180 ),
	change_90( Queens180, Queens270, N ),
	ck_min( Queens, Queens270 ),
	
	change_l/r( Queens, QueensM0, N ),
	ck_min( Queens, QueensM0 ),
	change_90( QueensM0, QueensM90, N ),
	ck_min( Queens, QueensM90 ),
	change_90( QueensM90, QueensM180, N ),
	ck_min( Queens, QueensM180 ),
	change_90( QueensM180, QueensM270, N ),
	ck_min( Queens, QueensM270 ),
	gvar(count, CNT),
	CNT1 is CNT + 1,
	set_gvar(count, CNT1).
%---------------------------------------------------------------------------%

% -- チェス盤に大小関係を定義して、より小さければ成功する -- %

ck_min( A, B ) :- 
%	sort_xy( B, B1 ),	% バブルソート   % 9233個 N=13,CPU time = 81057 msec
	quicksort_xy( B, B1 ),	% クイックソート % 9233個 N=13,CPU time = 63292 msec
	ck( A, B1 ).
%---------------------------------------------------------------------------%

% 左側から縦に上から下に向かって、2つのチェス盤をしらべていき、より早くクイーンに出会った ほうが小さいことにする。

ck( [], [] ).
ck( [_/Y1|L1], [_/Y2|L2] ) :-
	Y1 =:= Y2
    ->
	ck( L1, L2 )
    ;
	Y1 < Y2.


%---------------------------------------------------------------------------%

% -- [Y1,Y2,....]形式から[1/Y1,2/Y2,....]形式へ変換 -- %

x/y( [], [], _ ):-!.
x/y( [A|L1], [B|L2], N ) :-
	B = N/A,
	N1 is N + 1,
	x/y( L1, L2, N1 ).
%---------------------------------------------------------------------------%

% -- 左右反転:ひっくり返す -- %

change_l/r( [], [], _ ) :- !.
change_l/r( [A/B|L1], [X/Y|L], N ) :-
	N1 is N + 1,
	X is N1 - A,
	Y is B,
	change_l/r( L1, L, N ).
%---------------------------------------------------------------------------%

% -- 反時計90度回転 -- %

change_90( [], [], _ ) :- !.
change_90( [A/B|L1], [X/Y|L], N ) :-
	N1 is N + 1,
	X is B,
	Y is N1 - A,
	change_90( L1, L, N ).
%---------------------------------------------------------------------------%

% -- [X1/Y1,X2/Y2,...]形式を X を対象にしてソート。[1/Y1,2/Y2,...]へ -- %

% --- バブルソート --- %

sort_xy( A, B ) :-
        swap( A, C ),
        !,
        sort_xy( C, B ).
sort_xy( A, A ).
swap( [A,B|C], [B,A|C] ) :-
	A = A1/_, B = B1/_,
        A1 > B1.
swap( [A|B], [A|C] ) :-
        swap( B, C ).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%

% -- [X1/Y1,X2/Y2,...]形式を X を対象にしてソート。[1/Y1,2/Y2,...]へ -- %

% --- クイックソート --- %

quicksort_xy( List, Sorted ) :-
	quicksort_xy_2( List, Sorted-[] ).
%---------------------------------------------------------------------------%
quicksort_xy_2( [], S-S ).
quicksort_xy_2( [A|Tail], B1-Z2 ) :-
	sprit( A, Tail, Small, Big ),
	quicksort_xy_2( Small, B1-[A|B2] ),
	quicksort_xy_2( Big,   B2-Z2 ).
%---------------------------------------------------------------------------%
sprit( _, [], [], [] ).
sprit( A, [B|Tail], [B|Small], Big ) :-
%	A > B, !,
	A = X1/_,
	B = X2/_,
	X1 > X2, !,
	sprit( A, Tail, Small, Big ).
sprit( A, [B|Tail], Small, [B|Big] ) :-
	sprit( A, Tail, Small, Big ).
%---------------------------------------------------------------------------%

実行例

love:uema% swipl -qs nqueens_fast_more.pl                                  [~/love/prolog]
?- main.
N Queens!!
N = 13.
[1,9,6,8,3,11,13,5,10,12,7,4,2] 1
[1,9,7,5,8,11,13,6,3,12,10,4,2] 2
[1,7,10,6,9,5,13,11,3,8,12,4,2] 3
[1,9,6,10,7,11,3,5,13,8,12,4,2] 4
[1,8,4,7,12,10,5,13,11,9,3,6,2] 5
[1,8,5,9,4,13,10,12,7,11,3,6,2] 6
[1,9,13,3,7,4,10,12,5,11,8,6,2] 7
[1,9,5,10,4,11,3,12,7,13,8,6,2] 8
[1,7,4,8,11,13,10,3,5,12,9,6,2] 9
[1,10,4,7,11,13,3,5,8,12,9,6,2] 10
[1,8,11,5,3,13,9,12,4,7,10,6,2] 11
[1,8,4,12,9,13,5,3,11,7,10,6,2] 12
[1,8,11,9,4,10,5,3,12,7,13,6,2] 13
[1,3,10,6,9,11,13,4,12,8,5,7,2] 14
<略>
[1,4,8,13,9,7,3,11,6,2,5,10,12] 9227
[1,6,4,9,13,8,3,11,2,7,5,10,12] 9228
[1,3,8,6,9,2,13,11,4,7,5,10,12] 9229
[1,4,7,9,13,3,8,11,5,2,6,10,12] 9230
[2,4,6,1,9,11,13,8,3,5,7,10,12] 9231
[1,6,4,7,13,11,9,2,5,3,8,10,12] 9232
[1,3,5,7,9,11,13,2,4,6,8,10,12] 9233
CPU time = 82175 msec
false.

?-


13クイーンが82秒(1分22秒)で求まりました。超高速です(^_^;)

次のように前の版では、13クイーンが、445秒(7分25秒)かかります。

[1,4,7,5,10,2,13,11,3,8,6,9,12] 9221
[2,4,8,11,5,1,10,6,13,3,7,9,12] 9222
[1,4,6,8,3,11,13,2,10,5,7,9,12] 9223
[1,7,5,8,11,13,3,9,6,4,2,10,12] 9224
[1,5,7,11,13,8,4,9,3,6,2,10,12] 9225
[1,8,4,13,7,9,11,5,2,6,3,10,12] 9226
[1,4,8,13,9,7,3,11,6,2,5,10,12] 9227
[1,6,4,9,13,8,3,11,2,7,5,10,12] 9228
[1,3,8,6,9,2,13,11,4,7,5,10,12] 9229
[1,4,7,9,13,3,8,11,5,2,6,10,12] 9230
[2,4,6,1,9,11,13,8,3,5,7,10,12] 9231
[1,6,4,7,13,11,9,2,5,3,8,10,12] 9232
[1,3,5,7,9,11,13,2,4,6,8,10,12] 9233
CPU time = 445840 msec
false.

?-


inserted by FC2 system