【问题标题】:Binomial Coefficient [Prolog]二项式系数 [序言]
【发布时间】:2018-04-23 03:21:31
【问题描述】:
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。

【问题讨论】:

  • 为什么需要 4 个参数?第 4 个似乎是多余的,可能会给你带来麻烦。摆脱它。您的 bc(N, N, ...) 案例应该有条件 N > 0 以便它不会与其他两个基本案例在真值上重叠。并且bc(M, N, ...) 应该具有M > N 的条件,因为这就是这种情况。如果您正确设置条件,则不需要削减。
  • 您能用自己的话解释一下为什么您认为上述尝试会产生正确的结果吗?您运行的查询是什么?
  • bc(2,4,RES,0),从那里:M=2,N=4,Result,Each Result。
  • 我需要用 M 和 N 的参数计算一个二项式系数

标签: prolog binomial-coefficients swi-prolog-for-sharing


【解决方案1】:

首先,让我们正确表述二项式系数的公式。 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 > 0N < 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
| ?- ;

【讨论】:

  • 您的代码中有两个拼写错误:目标N>0M>N。有了这些,您的示例查询 ?- bc(4,X,6). 会导致实例化错误。您可能是指N#>0M#>N。此外,如果您在递归目标之前添加目标R #>= M,则类似?- bc(X,2,15). 的查询将终止。如果你看一下帕斯卡的三角形,系数要么是1(被你的事实所覆盖)要么是R,那么它出现的最后一行是与R相关的那一行,在第二个和下一个选择N-到最后的位置。 ;-)
  • @tas 谢谢!我没有用我最新的“修复”更新我的帖子,所以感谢你抓住它们。我在比我展示的更晚的代码上运行了我的示例。
  • 我能感觉到你,因为我自己也容易发生这种不幸:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-20
相关资源
最近更新 更多