Prolog中解决农民-山羊-狼-卷心菜问题的优化
我正在为经典的“狼、山羊和卷心菜”问题,在Prolog中寻找一种更好的算法,计算效率更高。下面的算法基于BFS搜索可能的情况 问题: “从前,一个农民去市场买了一只狼、一只山羊和一棵卷心菜。在回家的路上,农民来到河岸边租了一艘船。但是坐船过河时,农民只能自己和他买的一棵菜:狼、山羊或卷心菜 如果无人看管,狼会吃掉山羊,或者山羊会吃掉卷心菜 农场主的挑战是把他自己和他买的东西带到河的对岸,让每一件东西都完好无损。他是怎么做到的?” 此问题的当前解决方案是:Prolog中解决农民-山羊-狼-卷心菜问题的优化,prolog,river-crossing-puzzle,Prolog,River Crossing Puzzle,我正在为经典的“狼、山羊和卷心菜”问题,在Prolog中寻找一种更好的算法,计算效率更高。下面的算法基于BFS搜索可能的情况 问题: “从前,一个农民去市场买了一只狼、一只山羊和一棵卷心菜。在回家的路上,农民来到河岸边租了一艘船。但是坐船过河时,农民只能自己和他买的一棵菜:狼、山羊或卷心菜 如果无人看管,狼会吃掉山羊,或者山羊会吃掉卷心菜 农场主的挑战是把他自己和他买的东西带到河的对岸,让每一件东西都完好无损。他是怎么做到的?” 此问题的当前解决方案是: writelist([H|T]):-
writelist([H|T]):-
write(H), writelist(T).
empty_stack([]).
stack(Top, Stack, [Top|Stack]).
member_stack(Element, Stack):-
member(Element, Stack).
reverse_print_stack(S):-
empty_stack(S).
reverse_print_stack(S):-
stack(E, Rest, S),
reverse_print_stack(Rest),
write(E), nl.
unsafe(state(X,Y,Y,C)):-
opp(X, Y).
unsafe(state(X,W,Y,Y)):-
opp(X, Y).
move(state(X,X,G,C), state(Y,Y,G,C)):-
opp(X,Y), not(unsafe(state(Y,Y,G,C))),
writelist(['try farmer takes wolf ',Y,Y,G,C]),nl.
move(state(X,W,X,C), state(Y,W,Y,C)):-
opp(X,Y), not(unsafe(state(Y,W,Y,C))),
writelist(['try farmer takes goat ',Y,W,Y,C]),nl.
move(state(X,W,G,X), state(Y,W,G,Y)):-
opp(X,Y), not(unsafe(state(Y,W,G,Y))),
writelist(['try farmer takes cabbage ',Y,W,G,Y]),nl.
move(state(X,W,G,C), state(Y,W,G,C)):-
opp(X,Y), not(unsafe(state(Y,W,G,C))),
writelist(['try farmer takes self ',Y,W,G,C]),nl.
move(state(F,W,G,C), state(F,W,G,C)):-
writelist([' BACKTRACK from: ',F,W,G,C]),nl,fail.
path(Goal, Goal, Been_stack):-
nl, write('Solution Path is: '), nl,
reverse_print_stack(Been_stack).
path(State, Goal, Been_stack):-
move(State, Next_state),
not(member_stack(Next_state, Been_stack)),
stack(Next_state, Been_stack, New_been_stack),
path(Next_state, Goal, New_been_stack),!.
opp(e,w).
opp(w,e).
go(Start, Goal):-
empty_stack(Empty_been_stack),
stack(Start, Empty_been_stack, Been_stack),
path(Start, Goal, Been_stack).
test:-go(state(w,w,w,w), state(e,e,e,e)). ```
这是一个经过清理/简化的版本(IMHO) 总的来说,没有太多需要优化的地方 这是通过状态空间对路径进行的标准深度优先搜索 对于广度优先搜索,需要另一种方法 可以尝试比线性扫描(即某种哈希表)更快地查找访问的状态,但对于长度为8的历史来说,这真的不值得
% The state indicates the position of: Farmer, Wolf, Goat, Cabbage
% which is always one of east ('e') or west ('w').
unsafe(state(e,w,w,_)). % Wolf and Goat are on the same border and the farmer ain't there
unsafe(state(w,e,e,_)). % Wolf and Goat are on the same border and the farmer ain't there
unsafe(state(e,_,w,w)). % Goat and Cabbage are on the same border and the farmer ain't there
unsafe(state(w,_,e,e)). % Goat and Cabbage are on the same border and the farmer ain't there
opp(e,w).
opp(w,e).
% Valid next state generation
move(state(X,X,G,C), state(Y,Y,G,C)):-
opp(X,Y),
\+ unsafe(state(Y,Y,G,C)),
format("try farmer takes wolf ~q -> ~q\n",[state(X,X,G,C), state(Y,Y,G,C)]).
move(state(X,W,X,C), state(Y,W,Y,C)):-
opp(X,Y),
\+ unsafe(state(Y,W,Y,C)),
format("try farmer takes goat ~q -> ~q\n",[state(X,W,X,C), state(Y,W,Y,C)]).
move(state(X,W,G,X), state(Y,W,G,Y)):-
opp(X,Y),
\+ unsafe(state(Y,W,G,Y)),
format("try farmer takes cabbage ~q -> ~q\n",[state(X,W,G,X), state(Y,W,G,Y)]).
move(state(X,W,G,C), state(Y,W,G,C)):-
opp(X,Y),
\+ unsafe(state(Y,W,G,C)),
format("try farmer takes self ~q -> ~q\n",[state(X,W,G,C), state(Y,W,G,C)]).
not_yet_seen(State,History) :- % will fail if member(State, History)
member(State, History),
!,
format("State ~q already seen\n",[State]),
fail.
not_yet_seen(_,_). % the replacement: success if \+ member(State, History)
path(State, State, History) :- % found a solution! (but maybe not the BEST solution)
!, % don't continue the search down this history
reverse(History,RevHistory),
maplist(term_to_atom,RevHistory,RevHistoryAtoms),
atomic_list_concat(RevHistoryAtoms, '->', OutputAtom),
length(History,L),
format("A solution of length ~d: ~q\n",[L,OutputAtom]).
path(CurState, FinalState, History) :-
move(CurState, NextState), % generate a safe next state
not_yet_seen(NextState, History), % that hasn't been seen yet
(true;(format("Backtracking from using ~q\n",[NextState]),fail)),
path(NextState, FinalState, [NextState|History]). % add it to the visited states and recurse
go(StartState, FinalState) :-
path(StartState, FinalState, [StartState]). % 3rd arg is "history"
test :-
go(state(w,w,w,w), % first everything is west
state(e,e,e,e)). % then everything is east
它找到了两个历史长度为8的解决方案:
?- test.
try farmer takes goat state(w,w,w,w) -> state(e,w,e,w)
try farmer takes goat state(e,w,e,w) -> state(w,w,w,w)
State state(w,w,w,w) already seen
try farmer takes self state(e,w,e,w) -> state(w,w,e,w)
try farmer takes wolf state(w,w,e,w) -> state(e,e,e,w)
try farmer takes wolf state(e,e,e,w) -> state(w,w,e,w)
State state(w,w,e,w) already seen
try farmer takes goat state(e,e,e,w) -> state(w,e,w,w)
try farmer takes goat state(w,e,w,w) -> state(e,e,e,w)
State state(e,e,e,w) already seen
try farmer takes cabbage state(w,e,w,w) -> state(e,e,w,e)
try farmer takes wolf state(e,e,w,e) -> state(w,w,w,e)
try farmer takes wolf state(w,w,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
try farmer takes goat state(w,w,w,e) -> state(e,w,e,e)
try farmer takes goat state(e,w,e,e) -> state(w,w,w,e)
State state(w,w,w,e) already seen
try farmer takes cabbage state(e,w,e,e) -> state(w,w,e,w)
State state(w,w,e,w) already seen
Backtracking from using state(e,w,e,e)
Backtracking from using state(w,w,w,e)
try farmer takes cabbage state(e,e,w,e) -> state(w,e,w,w)
State state(w,e,w,w) already seen
try farmer takes self state(e,e,w,e) -> state(w,e,w,e)
try farmer takes goat state(w,e,w,e) -> state(e,e,e,e)
A solution of length 8: 'state(w,w,w,w)->state(e,w,e,w)->state(w,w,e,w)->state(e,e,e,w)->state(w,e,w,w)->state(e,e,w,e)->state(w,e,w,e)->state(e,e,e,e)'
true ;
Backtracking from using state(e,e,e,e)
try farmer takes self state(w,e,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,e)
Backtracking from using state(e,e,w,e)
Backtracking from using state(w,e,w,w)
Backtracking from using state(e,e,e,w)
try farmer takes cabbage state(w,w,e,w) -> state(e,w,e,e)
try farmer takes goat state(e,w,e,e) -> state(w,w,w,e)
try farmer takes wolf state(w,w,w,e) -> state(e,e,w,e)
try farmer takes wolf state(e,e,w,e) -> state(w,w,w,e)
State state(w,w,w,e) already seen
try farmer takes cabbage state(e,e,w,e) -> state(w,e,w,w)
try farmer takes goat state(w,e,w,w) -> state(e,e,e,w)
try farmer takes wolf state(e,e,e,w) -> state(w,w,e,w)
State state(w,w,e,w) already seen
try farmer takes goat state(e,e,e,w) -> state(w,e,w,w)
State state(w,e,w,w) already seen
Backtracking from using state(e,e,e,w)
try farmer takes cabbage state(w,e,w,w) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,w)
try farmer takes self state(e,e,w,e) -> state(w,e,w,e)
try farmer takes goat state(w,e,w,e) -> state(e,e,e,e)
A solution of length 8: 'state(w,w,w,w)->state(e,w,e,w)->state(w,w,e,w)->state(e,w,e,e)->state(w,w,w,e)->state(e,e,w,e)->state(w,e,w,e)->state(e,e,e,e)'
true ;
Backtracking from using state(e,e,e,e)
try farmer takes self state(w,e,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,e)
Backtracking from using state(e,e,w,e)
try farmer takes goat state(w,w,w,e) -> state(e,w,e,e)
State state(e,w,e,e) already seen
Backtracking from using state(w,w,w,e)
try farmer takes cabbage state(e,w,e,e) -> state(w,w,e,w)
State state(w,w,e,w) already seen
Backtracking from using state(e,w,e,e)
try farmer takes self state(w,w,e,w) -> state(e,w,e,w)
State state(e,w,e,w) already seen
Backtracking from using state(w,w,e,w)
Backtracking from using state(e,w,e,w)
false.
这是一个经过清理/简化的版本(IMHO) 总的来说,没有太多需要优化的地方 这是通过状态空间对路径进行的标准深度优先搜索 对于广度优先搜索,需要另一种方法 可以尝试比线性扫描(即某种哈希表)更快地查找访问的状态,但对于长度为8的历史来说,这真的不值得
% The state indicates the position of: Farmer, Wolf, Goat, Cabbage
% which is always one of east ('e') or west ('w').
unsafe(state(e,w,w,_)). % Wolf and Goat are on the same border and the farmer ain't there
unsafe(state(w,e,e,_)). % Wolf and Goat are on the same border and the farmer ain't there
unsafe(state(e,_,w,w)). % Goat and Cabbage are on the same border and the farmer ain't there
unsafe(state(w,_,e,e)). % Goat and Cabbage are on the same border and the farmer ain't there
opp(e,w).
opp(w,e).
% Valid next state generation
move(state(X,X,G,C), state(Y,Y,G,C)):-
opp(X,Y),
\+ unsafe(state(Y,Y,G,C)),
format("try farmer takes wolf ~q -> ~q\n",[state(X,X,G,C), state(Y,Y,G,C)]).
move(state(X,W,X,C), state(Y,W,Y,C)):-
opp(X,Y),
\+ unsafe(state(Y,W,Y,C)),
format("try farmer takes goat ~q -> ~q\n",[state(X,W,X,C), state(Y,W,Y,C)]).
move(state(X,W,G,X), state(Y,W,G,Y)):-
opp(X,Y),
\+ unsafe(state(Y,W,G,Y)),
format("try farmer takes cabbage ~q -> ~q\n",[state(X,W,G,X), state(Y,W,G,Y)]).
move(state(X,W,G,C), state(Y,W,G,C)):-
opp(X,Y),
\+ unsafe(state(Y,W,G,C)),
format("try farmer takes self ~q -> ~q\n",[state(X,W,G,C), state(Y,W,G,C)]).
not_yet_seen(State,History) :- % will fail if member(State, History)
member(State, History),
!,
format("State ~q already seen\n",[State]),
fail.
not_yet_seen(_,_). % the replacement: success if \+ member(State, History)
path(State, State, History) :- % found a solution! (but maybe not the BEST solution)
!, % don't continue the search down this history
reverse(History,RevHistory),
maplist(term_to_atom,RevHistory,RevHistoryAtoms),
atomic_list_concat(RevHistoryAtoms, '->', OutputAtom),
length(History,L),
format("A solution of length ~d: ~q\n",[L,OutputAtom]).
path(CurState, FinalState, History) :-
move(CurState, NextState), % generate a safe next state
not_yet_seen(NextState, History), % that hasn't been seen yet
(true;(format("Backtracking from using ~q\n",[NextState]),fail)),
path(NextState, FinalState, [NextState|History]). % add it to the visited states and recurse
go(StartState, FinalState) :-
path(StartState, FinalState, [StartState]). % 3rd arg is "history"
test :-
go(state(w,w,w,w), % first everything is west
state(e,e,e,e)). % then everything is east
它找到了两个历史长度为8的解决方案:
?- test.
try farmer takes goat state(w,w,w,w) -> state(e,w,e,w)
try farmer takes goat state(e,w,e,w) -> state(w,w,w,w)
State state(w,w,w,w) already seen
try farmer takes self state(e,w,e,w) -> state(w,w,e,w)
try farmer takes wolf state(w,w,e,w) -> state(e,e,e,w)
try farmer takes wolf state(e,e,e,w) -> state(w,w,e,w)
State state(w,w,e,w) already seen
try farmer takes goat state(e,e,e,w) -> state(w,e,w,w)
try farmer takes goat state(w,e,w,w) -> state(e,e,e,w)
State state(e,e,e,w) already seen
try farmer takes cabbage state(w,e,w,w) -> state(e,e,w,e)
try farmer takes wolf state(e,e,w,e) -> state(w,w,w,e)
try farmer takes wolf state(w,w,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
try farmer takes goat state(w,w,w,e) -> state(e,w,e,e)
try farmer takes goat state(e,w,e,e) -> state(w,w,w,e)
State state(w,w,w,e) already seen
try farmer takes cabbage state(e,w,e,e) -> state(w,w,e,w)
State state(w,w,e,w) already seen
Backtracking from using state(e,w,e,e)
Backtracking from using state(w,w,w,e)
try farmer takes cabbage state(e,e,w,e) -> state(w,e,w,w)
State state(w,e,w,w) already seen
try farmer takes self state(e,e,w,e) -> state(w,e,w,e)
try farmer takes goat state(w,e,w,e) -> state(e,e,e,e)
A solution of length 8: 'state(w,w,w,w)->state(e,w,e,w)->state(w,w,e,w)->state(e,e,e,w)->state(w,e,w,w)->state(e,e,w,e)->state(w,e,w,e)->state(e,e,e,e)'
true ;
Backtracking from using state(e,e,e,e)
try farmer takes self state(w,e,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,e)
Backtracking from using state(e,e,w,e)
Backtracking from using state(w,e,w,w)
Backtracking from using state(e,e,e,w)
try farmer takes cabbage state(w,w,e,w) -> state(e,w,e,e)
try farmer takes goat state(e,w,e,e) -> state(w,w,w,e)
try farmer takes wolf state(w,w,w,e) -> state(e,e,w,e)
try farmer takes wolf state(e,e,w,e) -> state(w,w,w,e)
State state(w,w,w,e) already seen
try farmer takes cabbage state(e,e,w,e) -> state(w,e,w,w)
try farmer takes goat state(w,e,w,w) -> state(e,e,e,w)
try farmer takes wolf state(e,e,e,w) -> state(w,w,e,w)
State state(w,w,e,w) already seen
try farmer takes goat state(e,e,e,w) -> state(w,e,w,w)
State state(w,e,w,w) already seen
Backtracking from using state(e,e,e,w)
try farmer takes cabbage state(w,e,w,w) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,w)
try farmer takes self state(e,e,w,e) -> state(w,e,w,e)
try farmer takes goat state(w,e,w,e) -> state(e,e,e,e)
A solution of length 8: 'state(w,w,w,w)->state(e,w,e,w)->state(w,w,e,w)->state(e,w,e,e)->state(w,w,w,e)->state(e,e,w,e)->state(w,e,w,e)->state(e,e,e,e)'
true ;
Backtracking from using state(e,e,e,e)
try farmer takes self state(w,e,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,e)
Backtracking from using state(e,e,w,e)
try farmer takes goat state(w,w,w,e) -> state(e,w,e,e)
State state(e,w,e,e) already seen
Backtracking from using state(w,w,w,e)
try farmer takes cabbage state(e,w,e,e) -> state(w,w,e,w)
State state(w,w,e,w) already seen
Backtracking from using state(e,w,e,e)
try farmer takes self state(w,w,e,w) -> state(e,w,e,w)
State state(e,w,e,w) already seen
Backtracking from using state(w,w,e,w)
Backtracking from using state(e,w,e,w)
false.
目前正在进行上述操作(可以大大简化…不需要使用helper谓词来扩展列表,因为Prolog程序员认识到列表扩展的含义),但这里有一个问题:“路径(下一个状态、目标、新的堆栈)!”。。。为什么要割伤?如果你想搜索,那么“提交”到当前选择的路径是没有意义的,毕竟,这只是一个猜测,一个暗中的尝试。不要在这里剪!另外,上面所说的绝对是深度优先搜索,而不是广度优先搜索(在这种情况下,建议使用迭代深化以避免内存使用的焦油坑)。移动生成器生成相同的状态,然后打印“回溯自”也没有什么意义。(好的,这意味着打印出安全移动生成失败的事实,作为一个catchall)“回溯”发生在路径/3中,尽管目前正在进行上述操作(它可以被大大简化…不需要使用帮助器谓词来扩展列表,因为Prolog程序员认识到列表扩展的本质)但这里有一个问题:“路径(下一个状态、目标、新的堆栈),!”。。。为什么要割伤?如果你想搜索,那么“提交”到当前选择的路径是没有意义的,毕竟,这只是一个猜测,一个暗中的尝试。不要在这里剪!另外,上面所说的绝对是深度优先搜索,而不是广度优先搜索(在这种情况下,建议使用迭代深化以避免内存使用的焦油坑)。移动生成器生成相同的状态,然后打印“回溯自”也没有什么意义。(好的,这意味着打印出安全移动生成失败的事实,作为一个总括)“回溯”发生在路径/3中。我正在搜索BFS优化和更大的历史记录,并且最佳答案将是最小的。路径的最小长度并最小化计算成本。我正在搜索BFS优化和更大的历史记录,并且最佳答案将是最小的。路径的最小长度和最小化计算成本。