【问题标题】:How to solve this arithmetic expression puzzle in Prolog?如何在 Prolog 中解决这个算术表达式难题?
【发布时间】:2015-05-08 23:59:47
【问题描述】:

我有一个编程问题 (https://blog.svpino.com/2015/05/08/solution-to-problem-5-and-some-other-thoughts-about-this-type-of-questions):

编写一个程序,输出所有在 + 或 - 之间放置的可能性 数字 1, 2, ..., 9(按此顺序)使得结果是 总是 100。例如:1 + 2 + 34 – 5 + 67 – 8 + 9 = 100。

我用 Python 解决了这个问题,得到 11 个答案

import itertools   
for operator in [p for p in itertools.product(['+','-',''], repeat=8)]:
    values = zip([str(x) for x in range(1, length+1)], operator) + ['9']
    code = ''.join(itertools.chain(*values))
    if 100 == eval(code):
        print "%s = %d" % (code, eval(code))

这是我的第二个较长的 Python 代码 (https://gist.github.com/prosseek/41201d6508f01cf1643e):

[1, 2, 34, -5, 67, -8, 9]
[1, 23, -4, 56, 7, 8, 9]
[12, 3, -4, 5, 67, 8, 9]
[123, -4, -5, -6, -7, 8, -9]
[1, 23, -4, 5, 6, 78, -9]
[12, 3, 4, 5, -6, -7, 89]
[12, -3, -4, 5, -6, 7, 89]
[123, -45, -67, 89]
[123, 45, -67, 8, -9]
[1, 2, 3, -4, 5, 6, 78, 9]
[123, 4, -5, 67, -89]

我还在 Prolog 中找到了一个建议的解决方案 (http://www.reddit.com/r/programming/comments/358tnp/five_programming_problems_every_software_engineer/cr2dvsz):

sum([Head|Tail],Signs,Result) :-
   sum(Head,Tail,Signs,Result).
sum(X,[],[],X).

sum(First,[Second|Tail],['+'|Signs],Result) :-
   Head is First + Second,
   sum(Head,Tail,Signs,Result).
sum(First,[Second|Tail],['-'|Signs],Result) :-
   Head is First - Second,
   sum(Head,Tail,Signs,Result).
sum(First,[Second|[Third|Tail]],['+'|[''|Signs]],Result) :- 
   C    is Second*10+Third, 
   Head is First + C, 
   sum(Head,Tail,Signs,Result).
sum(First,[Second|[Third|Tail]],['-'|[''|Signs]],Result) :-
   C    is Second*10+Third,
   Head is First - C,
   sum(Head,Tail,Signs,Result).

但是,这只提供了 4 个解决方案(不是预期的 11 个):

?- sum([1,2,3,4,5,6,7,8,9],X,100).
X = [+, +, -,+, +, +,'',+] ;
X = [+, +,'',-, + '', -,+] ;
X = [+,'', -,+, +, +,'',-] ;
X = [+,'', -,+ '', +, +,+] ;
false.

这是因为'' 没有作为第一个列表项出现。所以解决方案[12,...][123,...] 被跳过了。

我尝试添加sum(First,[Second|Tail],[''|Signs],Result) :- Head is First*10 + Second, sum(Head,Tail,Signs,Result)., 但这样做会返回 15 个解决方案,而不是 11 个。

解释说 1+23((1)+2)*10+3 的解释错误。

?- sum([1,2,3], [+,''], Result). 
Result = 33.

那么,如何在 Prolog 中解决这个问题呢?这个例子中如何教Prolog 1 + 2324

【问题讨论】:

    标签: python prolog constraints


    【解决方案1】:

    Python eval 的对应物可以用read_term/3is/2 来实现,或者

    give_100(A) :-
        generate(1, S),
        atomic_list_concat(S, A),
        read_term_from_atom(A, T, []),
        T =:= 100.
    
    generate(9, [9]).
    generate(N, [N|Ns]) :-
        N < 9, sep(N, Ns).
    
    sep(N, L) :-
        ( L = [+|Ns] ; L = [-|Ns] ; L = Ns ),
        M is N+1,
        generate(M, Ns).
    

    示例查询:

    ?- give_100(X).
    X = '1+2+3-4+5+6+78+9' ;
    X = '1+2+34-5+67-8+9' ;
    X = '1+23-4+5+6+78-9' ;
    X = '1+23-4+56+7+8+9' ;
    X = '12+3+4+5-6-7+89' ;
    X = '12+3-4+5+67+8+9' ;
    X = '12-3-4+5-6+7+89' ;
    X = '123+4-5+67-89' ;
    X = '123+45-67+8-9' ;
    X = '123-4-5-6-7+8-9' ;
    X = '123-45-67+89' ;
    false.
    

    【讨论】:

      【解决方案2】:

      使用,我们首先定义nonterminalsep//0

      sep --> "+" | "-" | "".
      

      然后,我们运行以下查询(使用 phrase/2sep//0read_from_codes/2(=:=)/2):

      ?- set_prolog_flag(double_quotes,chars).
      true.
      
      ?- phrase(("1",sep,"2",sep,"3",sep,"4",sep,"5",sep,"6",sep,"7",sep,"8",sep,"9"),Cs),
         read_from_codes(Cs,Expr),
         Expr =:= 100.
        Cs = [1,+,2,+,3,-,4,+,5,+,6,+,7,8,+,9], Expr = 1+2+3-4+5+6+78+9
      ; Cs = [1,+,2,+,3,4,-,5,+,6,7,-,8,+,9],   Expr = 1+2+34-5+67-8+9
      ; Cs = [1,+,2,3,-,4,+,5,+,6,+,7,8,-,9],   Expr = 1+23-4+5+6+78-9
      ; Cs = [1,+,2,3,-,4,+,5,6,+,7,+,8,+,9],   Expr = 1+23-4+56+7+8+9
      ; Cs = [1,2,+,3,+,4,+,5,-,6,-,7,+,8,9],   Expr = 12+3+4+5-6-7+89
      ; Cs = [1,2,+,3,-,4,+,5,+,6,7,+,8,+,9],   Expr = 12+3-4+5+67+8+9
      ; Cs = [1,2,-,3,-,4,+,5,-,6,+,7,+,8,9],   Expr = 12-3-4+5-6+7+89
      ; Cs = [1,2,3,+,4,-,5,+,6,7,-,8,9],       Expr = 123+4-5+67-89
      ; Cs = [1,2,3,+,4,5,-,6,7,+,8,-,9],       Expr = 123+45-67+8-9
      ; Cs = [1,2,3,-,4,-,5,-,6,-,7,+,8,-,9],   Expr = 123-4-5-6-7+8-9
      ; Cs = [1,2,3,-,4,5,-,6,7,+,8,9],         Expr = 123-45-67+89
      ; false.
      

      【讨论】:

      • 使用:- set_prolog_flag(double_quotes, chars). 使答案更具可读性。
      • @false。谢谢!现在好多了。
      【解决方案3】:

      与 CapelliC 的解决方案非常相似,但适用于 SWI-Prolog 和模块 lambda:

      :- use_module(library(lambda)).
      
      sum_100(Atom) :-
          L = [1,2,3,4,5,6,7,8,9],
          O = [_A,_B,_C,_D,_E,_F,_G,_H,' '],
          maplist(\X^member(X, [+,-,' ']), O),
          foldl(\X^Y^Z^T^(Y = ' '
                          ->  append(Z,[X], T)
                          ;   append(Z,[X,Y], T)), L, O, [], Expr),
          atomic_list_concat(Expr, Atom),
          term_to_atom(Term, Atom),
          Term =:= 100.
      

      示例查询:

      ?- sum_100(X).
      X = '1+2+3-4+5+6+78+9' ;
      X = '1+2+34-5+67-8+9' ;
      X = '1+23-4+5+6+78-9' ;
      X = '1+23-4+56+7+8+9' ;
      X = '12+3+4+5-6-7+89' ;
      X = '12+3-4+5+67+8+9' ;
      X = '12-3-4+5-6+7+89' ;
      X = '123+4-5+67-89' ;
      X = '123+45-67+8-9' ;
      X = '123-4-5-6-7+8-9' ;
      X = '123-45-67+89' ;
      false.
      

      【讨论】:

        猜你喜欢
        • 2023-03-27
        • 2015-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-02
        • 2013-09-12
        • 1970-01-01
        相关资源
        最近更新 更多