bc(0,N,R,R):- N>0,R is 1,!.
bc(M,0,R,R):- M>0,R is 1,!.
bc(N,N,R,R):- R is 1,!.
bc(M,N,R,R1):-
M1 is M - 1,
N1 is N - 1,
bc(M1,N1,R,R2),
bc(M1,N,R,R3),
R1 is R2+R3.
为什么会返回false?
任务是:编写递归过程C(M,N) (0 ≤ m ≤ n )
以使用此公式找出二项式系数:
C(m,0)=C(0,n)=C(n,n)=1
C(m,n)=C(m−1,n−1)+C(m−1,n)
P.S。:我使用在线编译器SWISH。
答案 0 :(得分:4)
首先,让我们正确地说明二项式系数的公式。 c(M, N)
的传统定义将M >= N >= 0
,而不是N >= M >= 0
。这很重要,因为给出了公式:
C(m,0)=C(0,n)=C(n,n)=1 C(m,n)=C(m−1,n−1)+C(m−1,n)
假定0 ≤ n ≤ m
,而不是(0 ≤ m ≤ n
)。所以它是不正确的(要么是错误的,要么你可能写错了)。此外,C(0, n)
除非n = 0
,否则不是有效系数。所以这种情况没有意义,可以省略。它已被C(m, 0)
覆盖。
问题的错误表述可能是导致结果“错误”的主要原因。
C(n, 0) = C(n, n) = 1
将由以下基础(非递归)案例涵盖:
bc(N, 0, 1) :- N #>= 0.
bc(N, N, 1) :- N #> 0. % The N = 0 case is already covered in the first base case
然后根据给定的公式递归处理更一般的情况:
bc(M, N, R) :-
N #> 0, % The N = 0 case is already covered in the first base case
M #> N, % The M = N case is already covered in the second base case
R #>= M, % This constraint prevents unbounded search in non-solution space
M1 #= M - 1, % The rest of this is just the given formula
N1 #= N - 1,
bc(M1, N1, R1),
bc(M1, N, R2),
R #= R1 + R2.
编写Prolog谓词时的一些原则:
确保准确无误地说明您的问题。这听起来很明显,但在这种情况下是一个问题。
使用CLP(FD)进行整数推理。这是Prolog所关注的更多关系。使用is/2
更多是命令式。例如,如果X is Y * 2
未绑定,Y
将生成实例化错误。但X #= Y * 2
会产生潜在的解决方案。如果由于任意要求而必须使用is/2
,则可以将其替换回来。
在谓词子句中应用约束,使它们互斥。也就是说,除非它是您想要的,否则不要让您的谓词对于给定的解决方案获得多种方式。特别是,使您的不同子句不重叠。例如,如果你有一个谓词,其中第一个参数是一个自然数(非负整数),并且你的基本情况是foo(0, 1).
,那么在你的递归情况foo(N, R) :-
中你需要约束N > 0
或N #> 0
,假设在递归情况下没有其他可能需要和/或不同的副作用或其他参数。
您可以在解决方案空间内约束或绑定变量的次数越多,您的代码就会越少尝试不是有效解决方案的选项,并且在最坏的情况下,由于缺少绑定而不会终止关于这种非解决方案的选择。例如,在此问题中,我们添加了约束R #>= M
,该约束在N > 0
和N < M
时为真。如果没有这个约束,Prolog将探索R < M
无限的情况,并在某些情况下导致无终止。
运行查询:
| ?- bc(3,2,R).
R = 3 ? ;
no
| ?- bc(4,2,R).
R = 6 ? ;
no
| ?-
等等...
通过使用CLP(FD)运算符,您还可以运行如下查询:
| ?- bc(4,X,6).
X = 2 ? ;
no
| ?-
和...
| ?- bc(N, K, 6).
N = 6
K = 1 ? ;
N = 4
K = 2 ? ;
N = 6
K = 5 ? ;
no
| ?- ;