最近刚接触正向推理方法( http://hyry.dip.jp:8000/cdtzx/program/prologadv24.htm ),接触了值域的概念,依然想从最简单的目标入手,比如用[1,2,3]的值域填一个3x3的表格,要求每行每列的数字各不相同,如
1,2,3
2,3,1
3,1,2
等,共12个解。这个目标用逆向推理法(生成所以可能的解,逐一检验)也容易实现。
但是我想试着用正向推理法,先找出第一行和第一列的值域,然后给第一个变量赋值,然后修改第一行和第一列的值域;找出第一行和第二列的值域,给第二个变量赋值,然后修给第一行和第二列的值域,以此类推,直到第九个变量。这样可以找到一个解,但之后回溯到第二行第二列的变量时出错,求前辈们指导。
assignS(s(X,Y,VS)):-(rl(X,Rl),rc(Y,Rc),intersection(Rl,Rc,RS)->RS\=[]),member(VS,RS),
%先求出每个格子s(X,Y,VS))关联的值域,然后求行值域和列值域交集,然后用member谓词从交集里面对VS赋值
subtract(Rl,[VS],Rl1),subtract(Rc,[VS],Rc1),
%生成新的行值域Rl1,和新的列值域Rc1,
asserta(rl(X,Rl1)),asserta(rc(Y,Rc1)).
%把新生成的值域写进内存,排在前面
sset([s(1,1,S11),s(1,2,S12),s(1,3,S13),s(2,1,S21),s(2,2,S22),s(2,3,S23),s(3,1,S31),s(3,2,S32),s(3,3,S33)]).
%初始化表格
%下面是主程序
assignment3x3cell(Sset):-
maplist(asserta,[rl(1,[1,2,3]),rl(2,[1,2,3]),rl(3,[1,2,3]),rc(1,[1,2,3]),rc(2,[1,2,3]),rc(3,[1,2,3])]),
/*初始化值域,rl(1,[1,2,3])表示第1行的值域为[1,2,3],rc(1,[1,2,3])表示第1列的值域为[1,2,3],*/
sset(Sset),maplist(assignS,Sset),
%用正向推理法把表填满
assert(count(0)),count(N),retract(count(0)),NN is N+1,write(NN),asserta(count(NN)),
(NN>1->retract(count(N));true),
%Liao sir教的计数方法
Sset =[s(1,1,S11),s(1,2,S12),s(1,3,S13),s(2,1,S21),s(2,2,S22),s(2,3,S23),s(3,1,S31),s(3,2,S32),s(3,3,S33)],
maplist(writeln,[(S11,S12,S13),(S21,S22,S23),(S31,S32,S33)]).
1,2,3
2,3,1
3,1,2
等,共12个解。这个目标用逆向推理法(生成所以可能的解,逐一检验)也容易实现。
但是我想试着用正向推理法,先找出第一行和第一列的值域,然后给第一个变量赋值,然后修改第一行和第一列的值域;找出第一行和第二列的值域,给第二个变量赋值,然后修给第一行和第二列的值域,以此类推,直到第九个变量。这样可以找到一个解,但之后回溯到第二行第二列的变量时出错,求前辈们指导。
assignS(s(X,Y,VS)):-(rl(X,Rl),rc(Y,Rc),intersection(Rl,Rc,RS)->RS\=[]),member(VS,RS),
%先求出每个格子s(X,Y,VS))关联的值域,然后求行值域和列值域交集,然后用member谓词从交集里面对VS赋值
subtract(Rl,[VS],Rl1),subtract(Rc,[VS],Rc1),
%生成新的行值域Rl1,和新的列值域Rc1,
asserta(rl(X,Rl1)),asserta(rc(Y,Rc1)).
%把新生成的值域写进内存,排在前面
sset([s(1,1,S11),s(1,2,S12),s(1,3,S13),s(2,1,S21),s(2,2,S22),s(2,3,S23),s(3,1,S31),s(3,2,S32),s(3,3,S33)]).
%初始化表格
%下面是主程序
assignment3x3cell(Sset):-
maplist(asserta,[rl(1,[1,2,3]),rl(2,[1,2,3]),rl(3,[1,2,3]),rc(1,[1,2,3]),rc(2,[1,2,3]),rc(3,[1,2,3])]),
/*初始化值域,rl(1,[1,2,3])表示第1行的值域为[1,2,3],rc(1,[1,2,3])表示第1列的值域为[1,2,3],*/
sset(Sset),maplist(assignS,Sset),
%用正向推理法把表填满
assert(count(0)),count(N),retract(count(0)),NN is N+1,write(NN),asserta(count(NN)),
(NN>1->retract(count(N));true),
%Liao sir教的计数方法
Sset =[s(1,1,S11),s(1,2,S12),s(1,3,S13),s(2,1,S21),s(2,2,S22),s(2,3,S23),s(3,1,S31),s(3,2,S32),s(3,3,S33)],
maplist(writeln,[(S11,S12,S13),(S21,S22,S23),(S31,S32,S33)]).