SWI-Prolog中的简单骑士和刀问题

时间:2019-05-14 21:01:58

标签: list prolog

我正在尝试使用针对N人数的生成和测试方法来解决“骑士和刀子”问题,以便获得以下结果:

?- find_knaves([3,2,1,4,2], Knaves).
Knaves = [1,0,0,1,0]

以上结果可以解释如下:

  • 第一个列表中的整数与人数一样多。
  • 每个人都提出索赔要求“我们中至少X是小刀” ,其中X是第一个列表中与每个人相对应的数字。
  • 1列表中以Knaves表示的人被证明是小刀。

我的方法:

我的想法是创建包含Knaves0的{​​{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

我的方法是否朝着正确的方向前进?如果没有,解决这个问题的最佳方法是什么?

1 个答案:

答案 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.