首先,让我们正确表述二项式系数的公式。 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 更为必要。例如,如果 Y 未绑定,X is Y * 2 将生成实例化错误。但是X #= Y * 2 会产生潜在的解决方案。如果由于任意要求必须使用is/2,则可以将其替换回去。
在谓词子句中应用约束,使它们互斥。也就是说,除非它是您想要的,否则对于给定的解决方案,不要让您的谓词以不止一种方式成功。特别是,使您的不同子句不重叠。例如,如果您有一个谓词,其中第一个参数是自然数(非负整数),并且您的基本情况为foo(0, 1).,那么在递归情况下foo(N, R) :- 您需要一个约束@987654340 @ 或 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
| ?- ;