递推与记忆化搜索

 内容参考书籍《算法竞赛入门到进阶》

先看一道经典题:poj1163 http://poj.org/problem?id=1163

 如果此题按照从上往下的方法计算,每走一步下一步就有2种选择,其复杂度为2n

那么我们从下往上算,下面给出dfs代码:

int dfs(int i,int j)
{
	if (i == n) return a[i][j];//递归到最后一行返回
	return dp[i][j] = max(dfs(i+1,j),dfs(i+1,j+1))+ a[i][j];
}

从1,1开始往下走,一直到最后一行,返回,每一次取能走到该点的最大值加上该点,继续返回,代码很好理解,只是复杂度为2n

下面我们再来讲一下递推,代码如下:

  for (int j = 1; j <= n; ++j) dp[n][j] = a[n][j];
  for (int i = n-1; i >= 1; --i)
  {
    for (int j = 1; j <= i; ++j)     {   dp[i][j] = max(dp[i+1][j],dp[i+1][j+1]) + a[i][j];     }
  }   cout<<dp[1][1]<<endl;

首先是第一层循环,将三角形最下面一层全部赋值给dp,然后从下往上求解,输出dp[1][1]即是最大值。这样复杂度便只有n2

那么搜索可以做到吗?当然可以,这就是我们说的记忆化,只需要在搜索算法中加入if即可,代码如下:

int dfs(int i,int j)
{
	if (i == n) return a[i][j];//递归到最后一行返回
	if (dp[i][j] >= 0) return dp[i][j];//记忆
	return dp[i][j] = max(dfs(i+1,j),dfs(i+1,j+1))+ a[i][j];
}

 这样搜索算法的复杂度也降到了n2,为什么要加这样一句话呢?我们可以发现,当我们从第2层的“3”往下走会经过“1”,计算一次从1出发的递归;从第2层的“8”往下走也会经过“1”,又重新计算了“1”出发的递归,为了避免这样的重复,使用记忆化便能避免,从而降低复杂度。

posted @ 2020-05-23 18:00  DemonSlayer  阅读(270)  评论(0编辑  收藏  举报