【问题标题】:Cryptarithmetic multiplication, any digits. Prolog密码乘法,任何数字。序言
【发布时间】:2022-10-15 09:03:53
【问题描述】:

我试图解决这个密码数学难题:

其中“*" 代表任何数字。

这是我到目前为止想出的代码。

permutation(Xs,[Z|Zs]) :-
    delete(Z,Xs,Ys),
    permutation(Ys,Zs).

delete(X,[X|Xs],Xs).
delete(X,[Y|Ys],[Y|Zs]) :-
    delete(X,Ys,Zs).

ca(A, B, C, D, E, F, G, H, I, J) :-
    permutation([1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
               [A, B, C, D, E, F, G, H, I, J]),
               (A*10000+B*1000+C*100+D*10+E*1) * (A * 1)
               =:=
               (_ * 100000 + _ * 10000 + H * 1000 + _ * 100 + _ * 10 + _ * 1).

我完全意识到 Prolog 不能简单地使用 _ 运算符解决这个等式。

我想弄清楚的是如何实现那些在我的代码中表示为单个下划线的不重要数字。

谢谢你的帮助。

【问题讨论】:

标签: prolog cryptarithmetic-puzzle


【解决方案1】:

.....
   mult1( [E,D,C,B,A], A, X), X= [_,_,_,H,_,_], 
   mult1( [E,D,C,B,A], G, Y), Y= [_,_,_,B,B], 
   mult1( [E,D,C,B,A], F, Z), Z= [_,_,_,H,_,_], 
   sum2( X, [0|Y], S), 
   sum2( S, [0,0|Z],             [_,_,D,_,_,_,F,_] ).

现在实现mult1sum2 使其工作。

为了提高效率,请使用

.....
   mselect( [A,B,C,D,E,H], [0,1,2,3,4,5,6,7,8,9], R1),
   .....
   mselect( [G], R1, R2),
   .....
   mselect( [F], R2, _),
   .....

% mselect/3 defined as
mselect( [A|B], C, R) :- select(A,C,D), mselect(B,D,R).
mselect( [], R, R).

我们根本不需要IJ。第一次乘法也不需要FG,第二次乘法也不需要F

根据构造,所有数字都会有所不同。

【讨论】:

    【解决方案2】:

    使用约束的解决方案:

    :- op(150, fx, #).
    
    base_(B, D, S0, S) :-
        #D #>= 0,
        #D #< #B,
        #S #= #D+ #B* #S0.
    
    puzzle(M, N) :-
        foldl(base_(10), [A,B,_,D,_], 0, M), #A #= 0,
        foldl(base_(10), [F,G,A], 0, N), #F #= 0,
    
        foldl(base_(10), [D0,_,H,_,_,_], 0, T0), #D0 #= 0,
        #T0 #= #M* #A,
        foldl(base_(10), [B,B,_,_,_], 0, T1), #B #= 0,
        #T1 #= #M* #G,
        foldl(base_(10), [D2,_,H,_,_,_], 0, T2), #D2 #= 0,
        #T2 #= #M* #F,
    
        foldl(base_(10), [D3,F,_,_,_,D,_,_], 0, T3), #D3 #= 0,
        #T3 #= #M* #N.
    
        % #T3 #= #T0+ #T1*10+ #T2*100. % Redundant constraints.
    

    查询:

    ?- puzzle(M, N), labeling([ff], [M,N]).
    

    【讨论】:

      【解决方案3】:

      按照 cmets (try this video to learn clpfd) 中的建议使用 clpfd 解决:

      :- use_module(library(clpfd)).
      
      % relates numbers to their digits, e.g. number_digits(123, [1,2,3]).
      number_digits(0, []).
      number_digits(Num, [D|Ds]) :-
          D in 0..9,
          Num #= D*10^Exp + Num0,
          length(Ds, Exp),
          number_digits(Num0, Ds).
      
      puzzle(Digits) :-
          Digits = [A,B,C,D,E,F,G,H],
          
          number_digits(Num1, [A,B,C,D,E]), 
          number_digits(Num2, [F,G,A]),
          
          Num3 #= Num1 * A,  
          number_digits(Num3, [_,_,H,_,_,_]),
          
          Num4 #= Num1 * G,
          number_digits(Num4, [B,B,_,_,_]),
          
          Num5 #= Num1 * F,
          number_digits(Num5, [_,_,H,_,_,_]),
          
          Num6 #= Num3 + Num4*10 + Num5*100,    
          number_digits(Num6, [_,F,_,_,_,D,_,_]),
          
          all_distinct(Digits),
          label(Digits).
      

      试用 SWIPL:https://swish.swi-prolog.org/p/NSmyRcuA.pl

      查询产生唯一的解决方案:

      ?- puzzle(Digits).
      Digits = [4, 9, 6, 0, 7, 5, 2, 8];
      

      【讨论】:

      • 它们被移动是因为该图说明了ABCDEFGA 的乘积。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-09
      • 1970-01-01
      相关资源
      最近更新 更多