QBXT2018 5 2 DP&图论班 记忆化搜索---思路简单的DP算法

对于一些刚学DP的同学,直接写出DP转移方程是有些困难的。这里张浩威(张过亿)dalao教给了我们一种简便的方法。可以先写出简单的暴力搜索,然后转成记忆化搜索。

优点:思路简单。

缺点:代码略难写,且很难优化。

例:01背包问题

首先可以写出最暴力的做法,即枚举每个物品选还是不选。

void dfs(int x,int y,int z) //x=当前物品编号,y=当前体积之和,z=当前价值之和
{
  if (x==n+1)
  {
    if (y<=m) ans=max(ans,z);
    return;
  }
  dfs(x+1,y+w[x],z+v[x]);
  dfs(x+1,y,z);
}
dfs(1,0,0);
时间复杂度为 O(2^n)

可以观察到当x和y固定时,z越大越好。

考虑将x y当成状态 z当成状态所代表的值。即dp[x][y]=z。然后把DFS的返回值改为int。

int dfs(int x,int y){
    if(y>t) return -inf;
    if(x==n+1){
        return 0;
    }
    if(dp[x][y]) return dp[x][y];
    dp[x][y]=max(dfs(x+1,y),dfs(x+1,y+w[x])+v[x]);
    return dp[x][y];
}

x=当前物品编号 y=当前体积之和 dp[x][y]=接下来还能获取的最大价值 t=背包体积。

因为y>t的情况显然不合法,因此dp[x][y](y>t)= -inf  即这种情况绝对不会成为最优答案。

if(x==n+1) 递归边界 接下来还能获取的价值为0,因此返回0。

if(dp[x][y]) 说明之前曾经遍历过这种情况。因为该题的状态不会因为DFS的不同而改变,即DFS(3,2)与DFS(3,4)都有可能遍历到当前情况,但不会因DFS的不同而不同,因此可以直接返回之前被遍历到时的值。

dp[x][y]=max(dfs(x+1,y),dfs(x+1,y+w[x])+v[x]); 有两种决策:选与不选,因此dp[x][y]会有上面两个值转移到。需要注意,dp[][]表示的是接下来能获取的最大价值,所以别忘了加上当前的贡献。

这就是记忆化搜索。

猜你喜欢

转载自www.cnblogs.com/Loi-Brilliant/p/8982639.html