最优子结构与记忆化搜索

源于对算法竞赛一书的理解

最优子结构:先来看一个数塔数塔
从最顶部的结点出发,每次可以向左或者向右走一格,走到最底部时把沿途经历的结点全部加起来,如何走才能和最大。
可以用一个二维数组a(i,j)记录这张数塔图,每一个结点的位置(i,j),都可以看作是一个状态,则从当前状态出发,下一个状态可以是(i+1,j)或者是(i+1,j+1),而题目就是求从状态(0,0)出发,不断的状态进行转移,转移到最底部时所得的和最大值。设d(0,0)为从状态(0,0)出发得到的和最大值,则d(0,0)=a(0,0)+d(1,0)或者d(0,0)=a(0,0)+d(1,1);要得到最大值只能是其中一种走法,所以d(0,0)=a(0,0)+max(d(1,0),d(1,1)),即当前最优解等于下一子状态的最优解加上当前结点值。当下一子状态都不是最优解时,当前状态一定不是最优解。这就是最优子结构。
递归算法如下:


int solve(int i,int j)
{
return d[i][j]=a[i][j]+(i==n?0:max(solve(i+1,j),solve(i+1,j+1));
}
但是这样做这道题,相当于从节点开始往下搜索,由于总共层数有n层,一共有2的n次-1个结点要被执行,所以 时间复杂度为o(2^n),过于复杂,这是因为有很多结点被重复执行了,比如从状态(2,1)要转移到(3,2),而从状态(2,2)也要转移到(3,2),这样从(3,2)这个结点往下的子树就被执行了两次,更何况,别的结点及以下的子树也会发生这种情况,时间复杂度就这样上来了。因此采用记忆化搜索来保证每个结点及以下的子树只走一次。
记忆化搜索:
如果把每从一个状态出发后所得的最优解记录在一个数组dp[i][j]中,那么当下一次又执行到这个状态时,就可以返回了,避免了重复操作。
代码int solve(int i,int j)
{
if(dp[i][j]>0)
return dp[i][j];
else
return dp[i][j]=a[i][j]+(i==n?0:max(solve(i+1,j),solve(i+1,j+1));
}

这里赋值语句本身有返回值。即把值赋给dp[i][j]后,又可以把dp[i][j]的值返回。

如果博文有什么误笔,错误欢迎留言指出。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值