算术谜题序言

Arithmetic puzzle prolog

我必须在该列表中的数字之间加上 + 和 - 才能获得提供的数字。例如 12-34 = -22。我是这样做的:

arit(L, Ls, S) :- arit(L, Ls, S, 0).
arit([], [], R, R).

arit([E|L], Ls, R, S) :- 
    S1 is S + E, 
    Ls = [+|[E|Ns]], 
    arit(L, Ns, R, S1).

arit([E|L], Ls, R, S) :- 
    S1 is S - E, 
    Ls = [-|[E|Ns]], 
    arit(L, Ns, R, S1).


arit([E|L], Ls, R, S) :- 
    S1 is (S*10 + E), 
    Ls=[E|Ns], 
    arit(L, Ns, R, S1).

有效,但答案重复(如 1+2+3 和 +1+2+3)。也许有人知道如何优化它?编辑。此代码根本不起作用,请查看答案。

实际上,您的代码无法正常工作。要确认这一事实,请尝试以下查询:

?- put_arit2([1,2,3,4], L, 22).
false.

很容易检查,[-,1,2,+,3,4] 是正确答案。

因此,我建议采用以下解决方案(在 SWI-Prolog 中):

  • 定义一个可以生成所有可能列表(带运算符)的谓词。
  • 将每一个可能的列表转化为对应的算术表达式,并检查其是否具有所需的值。
% putop(+List, -ListWithOperators)

putop([], []).
putop(L, [O|D]) :-
    member(O, [+,-]),
    append([X|A], B, L), % split list into two sublists, such that first one is not empty 
    append([X|A], C, D), % append first sublist with the sublist that will be obtained recursively
    putop(B, C).

% putop(+List, -ListWithOperators, +DesiredValue)

putop(L, E, V) :-
     putop(L, E),                   % obtain list with operators
     atomic_list_concat(E, A),      % transform list into an atom
     read_term_from_atom(A, T, []), % transfom atom into a term
     V is T.                        % check whether term has the desired value

示例:

?- putop([1,2,3,4], L, 22).
L = [-, 1, 2, +, 3, 4] ;
false.

?- putop([1,2,3,4,5,6,7,8,9], L, 4).
L = [+, 1, +, 2, -, 3, 4, +, 5, +, 6, +, 7, +, 8, +, 9] ;
L = [+, 1, 2, +, 3, -, 4, +, 5, -, 6, -, 7, -, 8, +, 9] ;
L = [+, 1, 2, +, 3, -, 4, -, 5, +, 6, -, 7, +, 8, -, 9] ;
L = [+, 1, 2, -, 3, +, 4, +, 5, -, 6, -, 7, +, 8, -, 9] ;
L = [+, 1, 2, -, 3, +, 4, -, 5, +, 6, +, 7, -, 8, -, 9] ;
L = [+, 1, 2, -, 3, +, 4, 5, -, 6, 7, +, 8, +, 9] ;
L = [+, 1, 2, -, 3, -, 4, -, 5, -, 6, -, 7, +, 8, +, 9] ;
L = [+, 1, 2, -, 3, 4, -, 5, 6, -, 7, +, 8, 9] ;
L = [-, 1, +, 2, +, 3, 4, +, 5, 6, -, 7, 8, -, 9] ;
L = [-, 1, +, 2, 3, +, 4, 5, +, 6, -, 7, 8, +, 9] ;
L = [-, 1, -, 2, +, 3, 4, -, 5, +, 6, 7, -, 8, 9] ;
L = [-, 1, -, 2, 3, -, 4, +, 5, 6, -, 7, -, 8, -, 9] ;
L = [-, 1, 2, +, 3, +, 4, +, 5, -, 6, -, 7, +, 8, +, 9] ;
L = [-, 1, 2, +, 3, +, 4, -, 5, +, 6, +, 7, -, 8, +, 9] ;
L = [-, 1, 2, +, 3, -, 4, +, 5, +, 6, +, 7, +, 8, -, 9] ;
L = [-, 1, 2, +, 3, -, 4, -, 5, -, 6, 7, +, 8, 9] ;
L = [-, 1, 2, -, 3, -, 4, +, 5, -, 6, +, 7, +, 8, +, 9] ;
L = [-, 1, 2, -, 3, 4, +, 5, 6, -, 7, -, 8, +, 9] ;
false.

[编辑] 如果您不想使用内置谓词 atomic_list_concat/2read_term_from_atom/3,那么您需要创建自己的谓词用于评估数字和运算符列表的谓词。

putop(L, E, V) :-
     putop(L, E),
     evaluate(E, V).

putop([], []).
putop(L, [O|D]) :-
    member(O, [+,-]),
    append([X|A], B, L),
    append([X|A], C, D),
    putop(B, C).

evaluate(List, Value) :-
    evaluate(List, 0, Value).

evaluate([], Value, Value).
evaluate([Operator|List], Accumulator, Value) :-
    operand(List, 0, Operand, Rest),
    add(Operator, Accumulator, Operand, NewAccumulator),
    evaluate(Rest, NewAccumulator, Value).

operand([], Accumulator, Accumulator, []).
operand([+|Rest], Accumulator, Accumulator, [+|Rest]).
operand([-|Rest], Accumulator, Accumulator, [-|Rest]).
operand([Digit|Rest], Accumulator, Value, List) :-
    Digit \= +,
    Digit \= -,
    NewAccumulator is 10*Accumulator + Digit,
    operand(Rest, NewAccumulator, Value, List).

add(+, Accumulator, Operand, NewAccumulator) :-
    NewAccumulator is Accumulator + Operand.
add(-, Accumulator, Operand, NewAccumulator) :-
    NewAccumulator is Accumulator - Operand.