我正在尝试使用针对N
人数的生成和测试方法来解决“骑士和刀子”问题,以便获得以下结果:
?- find_knaves([3,2,1,4,2], Knaves).
Knaves = [1,0,0,1,0]
以上结果可以解释如下:
X
是小刀” ,其中X
是第一个列表中与每个人相对应的数字。1
列表中以Knaves
表示的人被证明是小刀。我的方法:
我的想法是创建包含Knaves
和0
的{{1}}列表的所有排列,然后过滤掉不符合人们要求的内容:
1
上面的代码创建了所有排列,但是现在我只能继续保持一个正确的排列。
我确定必须进行递归,我必须遍历evaluate([], _).
evaluate([Head|Tail], List) :-
member(Head, List),
evaluate(Tail, List).
permute(Number, List, Permutations) :-
length(Permutations, Number),
evaluate(Permutations, List).
find_knaves(Statements, Results) :-
length(Statements, FriendsNumber),
permute(FriendsNumber, [0, 1], Results).
列表,但是然后我不确定条件应该是什么。我在考虑以下几行内容(伪代码):
Statements
我的方法是否朝着正确的方向前进?如果没有,解决这个问题的最佳方法是什么?
答案 0 :(得分:3)
这里是对您的解决方案的最小补充(略微重命名了一些谓词):
enumerate_n(N, Symbols, R) :-
length(R, N),
enumerate_n(R, Symbols).
enumerate_n([], _).
enumerate_n([X|Xs], Symbols) :-
member(X, Symbols),
enumerate_n(Xs, Symbols).
check_statements(Statements, Solution) :-
length(Statements, N),
enumerate_n(N, [0,1], Solution),
include(==(1), Solution, Knaves),
length(Knaves, N_knaves),
maplist(validate(N_knaves), Statements, Solution).
validate(Knaves, Statement, 0) :-
Statement =< Knaves.
validate(Knaves, Statement, 1) :-
Statement > Knaves.
它可以解决您的示例:
?- check_statements([3,2,1,4,2], S).
S = [1, 0, 0, 1, 0] ;
false.
它报告没有其他解决方案。
编辑:您可以得到一点点聪明,并通过汇总列表来数出刀数。
代替:
include(==(1), Solution, Knaves),
length(Knaves, N_knaves)
您可以写:
sum_list(Solution, N_knaves)
您可以使用same_length/2
代替length/2
。您也可以用maplist
替换递归谓词。代码变为:
statements_knaves(S, K) :-
same_length(S, K),
maplist(knave_or_knight, K),
sum_list(K, N),
maplist(validate(N), S, K).
knave_or_knight(0).
knave_or_knight(1).
validate(N, X, 0) :- X =< N.
validate(N, X, 1) :- X > N.