3

我正在尝试在 Prolog 中编写一个程序来找到一个大小为 N 的拉丁方。

我现在有这个:

delete(X, [X|T], T).
delete(X, [H|T], [H|S]) :-
   delete(X, T, S).

permutation([], []).
permutation([H|T], R) :-
   permutation(T, X),
   delete(H, R, X).

latinSqaure([_]).
latinSquare([A,B|T], N) :-
   permutation(A,B),
   isSafe(A,B),
   latinSquare([B|T]).

isSafe([], []).
isSafe([H1|T1], [H2|T2]) :- 
   H1 =\= H2, 
   isSafe(T1, T2).
4

3 回答 3

2

使用 SWI-Prolog 库:

:- module(latin_square, [latin_square/2]).
:- use_module(library(clpfd), [transpose/2]).

latin_square(N, S) :-
    numlist(1, N, Row),
    length(Rows, N),
    maplist(copy_term(Row), Rows),
    maplist(permutation, Rows, S),
    transpose(S, T),
    maplist(valid, T).

valid([X|T]) :-
    memberchk(X, T), !, fail.
valid([_|T]) :- valid(T).
valid([_]).

测试:

?- aggregate(count,S^latin_square(4,S),C).
C = 576.

编辑您的代码,一旦更正删除拼写错误,它就是一个验证器,而不是一个生成器,但是(正如 ssBarBee 在已删除的评论中所指出的那样),它存在缺陷,因为缺少对不相邻行的测试。这里是更正的代码

delete(X, [X|T], T).
delete(X, [H|T], [H|S]) :-
    delete(X, T, S).

permutation([], []).
permutation([H|T], R):-
    permutation(T, X),
    delete(H, R, X).

latinSquare([_]).
latinSquare([A,B|T]) :-
    permutation(A,B),
    isSafe(A,B),
    latinSquare([B|T]).

isSafe([], []).
isSafe([H1|T1], [H2|T2]) :-
    H1 =\= H2,
    isSafe(T1, T2).

和一些测试

?- latinSquare([[1,2,3],[2,3,1],[3,2,1]]).
false.

?- latinSquare([[1,2,3],[2,3,1],[3,1,2]]).
true .

?- latinSquare([[1,2,3],[2,3,1],[1,2,3]]).
true .

注意最后一次测试它是错误的,应该false改为。

于 2012-12-16T23:03:55.133 回答
1

像@CapelliC 一样,我建议为此使用 CLP(FD) 约束,这些约束在所有严肃的 Prolog 系统中都可用。

事实上,考虑更普遍地使用约束,以从约束传播中受益。

例如:

:- use_module(library(clpfd)).

latin_square(N, Rows, Vs) :-
        length(Rows, N),
        maplist(same_length(Rows), Rows),
        maplist(all_distinct, Rows),
        transpose(Rows, Cols),
        maplist(all_distinct, Cols),
        append(Rows, Vs),
        Vs ins 1..N.

例如,计算 的所有解决方案N = 4

?- findall(., (latin_square(4,_,Vs),labeling([ff],Vs)), Ls), 长度(Ls, L)。
L = 576 ,
LS = [...]。

CLP(FD) 版本比其他版本快得多。

请注意,将核心关系与实际搜索分开是一种很好的做法labeling/2。这使您可以快速看到核心关系也终止于较大的N

?- latin_square(20, _, _), 假的。
错误的。

因此,我们直接看到 this 终止,因此 this 加上任何后续搜索labeling/2都可以保证找到所有解决方案。

于 2015-10-19T09:11:45.340 回答
1

我有更好的解决方案,@CapelliC 代码对于 N 长度大于 5 的正方形需要很长时间。

:- use_module(library(clpfd)).

make_square(0,_,[]) :- !.
make_square(I,N,[Row|Rest]) :-
   length(Row,N),
   I1 is I - 1,
   make_square(I1,N,Rest).

 all_different_in_row([]) :- !.
 all_different_in_row([Row|Rest]) :-
    all_different(Row),
    all_different_in_row(Rest).


all_different_in_column(Square) :-
   transpose(Square,TSquare),
   all_different_in_row(TSquare).   

all_different_in_column1([[]|_]) :- !.
all_different_in_column1(Square) :-
   maplist(column,Square,Column,Rest),
   all_different(Column),
   all_different_in_column1(Rest).


   latin_square(N,Square) :-
   make_square(N,N,Square),
   append(Square,AllVars),
   AllVars ins 1..N,
   all_different_in_row(Square),
   all_different_in_column(Square),
   labeling([ff],AllVars).
于 2016-01-20T10:03:18.763 回答