首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >最大子阵(Kadane算法)-尾递归

最大子阵(Kadane算法)-尾递归
EN

Stack Overflow用户
提问于 2016-03-30 13:38:52
回答 3查看 814关注 0票数 3

我试图在Prolog中实现卡达内算法。要求之一是尾调用(递归)。

我尝试过许多可能性,但都没有成功。这是我的代码:

代码语言:javascript
复制
max_sum(L, S) :-
    S is 0,
    H is 0,
    max_sum(L, H, S).

max_sum([], S, S).
max_sum([X | L], H, S) :-
    (   H + X < 0 -> NewH is 0; NewH is H + X),
    (   S < H + X -> NewS is NewH; NewS is S),
    length(L, N),
    (   N < 1 -> max_sum(L, NewS, NewS); max_sum(L, NewH, NewS)).

NewH,NewS是临时值(我们不能在Prolog中两次分配一个值,对吗?)能给我个提示吗?

编辑:

代码语言:javascript
复制
[trace]  ?- max_sum([1, 2, 3], S).
   Call: (7) max_sum([1, 2, 3], _G8907) ? creep
   Call: (8) _G8907 is 0 ? creep
   Exit: (8) 0 is 0 ? creep
   Call: (8) _G8991 is 0 ? creep
   Exit: (8) 0 is 0 ? creep
   Call: (8) max_sum([1, 2, 3], 0, 0) ? creep
   Call: (9) 0+1<0 ? creep
   Fail: (9) 0+1<0 ? creep
   Redo: (8) max_sum([1, 2, 3], 0, 0) ? creep
   Call: (9) _G8994 is 0+1 ? creep
   Exit: (9) 1 is 0+1 ? creep
   Call: (9) 0<0+1 ? creep
   Exit: (9) 0<0+1 ? creep
   Call: (9) _G8997 is 1 ? creep
   Exit: (9) 1 is 1 ? creep
   Call: (9) length([2, 3], _G8998) ? creep
   Exit: (9) length([2, 3], 2) ? creep
   Call: (9) 2<1 ? creep
   Fail: (9) 2<1 ? creep
   Redo: (8) max_sum([1, 2, 3], 0, 0) ? creep
   Call: (9) max_sum([2, 3], 1, 1) ? creep
   Call: (10) 1+2<0 ? creep
   Fail: (10) 1+2<0 ? creep
   Redo: (9) max_sum([2, 3], 1, 1) ? creep
   Call: (10) _G9000 is 1+2 ? creep
   Exit: (10) 3 is 1+2 ? creep
   Call: (10) 1<1+2 ? creep
   Exit: (10) 1<1+2 ? creep
   Call: (10) _G9003 is 3 ? creep
   Exit: (10) 3 is 3 ? creep
   Call: (10) length([3], _G9004) ? creep
   Exit: (10) length([3], 1) ? creep
   Call: (10) 1<1 ? creep
   Fail: (10) 1<1 ? creep
   Redo: (9) max_sum([2, 3], 1, 1) ? creep
   Call: (10) max_sum([3], 3, 3) ? creep
   Call: (11) 3+3<0 ? creep
   Fail: (11) 3+3<0 ? creep
   Redo: (10) max_sum([3], 3, 3) ? creep
   Call: (11) _G9006 is 3+3 ? creep
   Exit: (11) 6 is 3+3 ? creep
   Call: (11) 3<3+3 ? creep
   Exit: (11) 3<3+3 ? creep
   Call: (11) _G9009 is 6 ? creep
   Exit: (11) 6 is 6 ? creep
   Call: (11) length([], _G9010) ? creep
   Exit: (11) length([], 0) ? creep
   Call: (11) 0<1 ? creep
   Exit: (11) 0<1 ? creep
   Call: (11) max_sum([], 6, 6) ? creep
   Exit: (11) max_sum([], 6, 6) ? creep
   Exit: (10) max_sum([3], 3, 3) ? creep
   Exit: (9) max_sum([2, 3], 1, 1) ? creep
   Exit: (8) max_sum([1, 2, 3], 0, 0) ? creep
   Exit: (7) max_sum([1, 2, 3], 0) ? creep

在Call(11)中,我从这个简单的例子中得到了一个好的结果(6)。如何在此结束此功能而不返回?这是我的问题。

此代码的结果是S= 0,而不是S= 6。

最后编辑(工作代码):

代码语言:javascript
复制
max_sum(L, S) :-
    max_sum(L, 0, 0, S).

max_sum([], _, S, S).
max_sum([X | L], H, F, S) :-
    NewH is max(0, H + X),
    (F < H + X -> NewF is NewH; NewF is F),
    max_sum(L, NewH, NewF, S).

其中:

  • 最后的结果,
  • F- maximum_so_far,
  • H- maximum_ending_here,
  • 名单上的X头,
  • L-名单,
  • NewH,NewF - temp值.

谢谢你的帮助:)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-04-05 02:32:08

我提议对@ 解决方案提出一个略为修改的版本:

代码语言:javascript
复制
:- use_module(library(clpfd)).

zs_max([Z|Zs], MSF) :-
   zs_max_(Zs, Z, Z, MSF).

zs_max_([], _, MSF, MSF).
zs_max_([Z|Zs], MEH0, MSF0, MSF) :-
   max(Z, MEH0+Z)  #= MEH1,
   max(MSF0, MEH1) #= MSF1,
   zs_max_(Zs, MEH1, MSF1, MSF).

首先,来自原始解决方案的示例查询结果相同:

代码语言:javascript
复制
   ?- zs_max([-2,1,-3,4,-1,2,1,-5,4], Max).
Max = 6
   ?- zs_max([-2,3,4,-5,8,-12,100,-101,7], Max).
Max = 100

但是,这个版本更普遍,因为它可以处理任意值(如解决方案注释中的@false所建议的那样)。这是从列表的第一个元素的值开始,而不是从0开始。因此,以下查询产生一个不同的结果:

代码语言:javascript
复制
   ?- zs_max([-2,-3,-4], X).
X = -2
   ?- zs_maxmum([-2,-3,-4], X).
X = 0

另一个不同之处是,空列表没有解决方案:

代码语言:javascript
复制
   ?- zs_max([], X).
no
   ?- zs_maxmum([], X).
X = 0

我认为这种行为更为合理,因为空列表没有子列表,因此也没有选择最大子列表的总子列表。但是,如果需要,可以很容易地添加空列表的特例:

代码语言:javascript
复制
zs_max([], replaceThisWithAReasonableValue).
票数 2
EN

Stack Overflow用户

发布于 2016-04-01 15:06:59

  1. 事实上,这个问题是"在Prolog中查找最大子列表“的重复。
  2. 因为有赏金,所以不能把它标记为副本。
  3. 我建议使用我的前解-it基于clpfd,并使用SWI运行。
票数 3
EN

Stack Overflow用户

发布于 2016-03-30 15:55:57

标准的方法是添加一个输出参数,该参数在递归停止时得到统一。有点像

代码语言:javascript
复制
max_sum(L, S) :-
    max_sum(L, 0, 0, S).

max_sum([], _, S, S).
...

然后,您的代码比所需的要复杂得多:维基百科上列出的两个版本都不需要任何测试或长度/2计算。尽量简化它,只留下计算(例如,可以使用Max_ending_here is max(0, H + X),和尾递归调用)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36310568

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档