3

我是 prolog 的新手,试图解决这个经典的硬币找零问题。

change(M,P,N,D) 用 M>=0 和 M = P+5*N+10*D 的公式这是我的方法

change(M,P,N,D) :-
     M is P+5*N+10*D,
     P is M - (5*N+10*10).

几个测试用例

  change(100,10,8,5).
  True
  change(X,10,8,5).
  X = 100.

但是,如果我尝试

 change(100,P,8,5).

它给了我“参数没有充分实例化”而不是 P = 10。这是什么原因?

编辑:通过使用介于(0,M,P),介于(0,M,N),介于(0,M,D)之间,M是P + 5 * N + 10 * D之间的谓词来修复我的代码。

4

1 回答 1

5

使用

:- use_module(library(clpfd)).

我们只需要表达change/4一个方程

change(Money,Pennies,Nickels,Dimes) :-
   Money #= Pennies + Nickels*5 + Dimes*10.

让我们运行 OP 给出的地面查询!

?- change(100,10,8,5).
true.

接下来,四个查询只有一个变量:

?- 改变(,10,8,5)。
金钱 = 100。

?- 变化(100,便士,8,5)。
便士 = 10。

?- 变化(100,10,,5)。
镍 = 8。

?- 变化(100,10,8, Dimes)。
硬币 = 5。

当我们使用时,我们还可以提出更一般的查询,比如这个带有三个变量的查询:

?- change(100,Pennies,Nickels,Dimes).
100 #= Pennies + 5*Nickels + 10*Dimes.

请注意,这并没有(还)枚举所有可能的组合......这样做需要两个步骤:

  1. 通过使用声明“所有计数都是非负数” ins/2

    ?- [便士、镍、角钱] ins 0..sup ,
       改变(100,便士,镍,角钱)。
    100 #= 便士 + 5*镍 + 10*角钱,
    0..100 美分,
    0..20 中的镍,
    0..10 美元。
    
  2. 使用枚举谓词labeling/2

    ?- Zs = [便士、镍、角钱],
       Zs ins 0..sup,
       零钱(100,便士,镍,角钱),
       标签([],Zs)。
      便士 = 0,镍币 = 0,硬币 = 10
    ; 便士 = 0,镍币 = 2,硬币 = 9
    ; 便士 = 0,镍币 = 4,一角硬币 = 8
    % 为简洁起见,省略了接下来的 115 个答案
    ; 便士 = 90,镍币 = 2,一角硬币 = 0
    ; 便士 = 95,镍币 = 1,硬币 = 0
    ; 便士 = 100,镍币 = 0,硬币 = 0
    ; 错误的。
    
于 2015-08-04T08:24:54.153 回答