0
点赞
收藏
分享

微信扫一扫

Dynamic Programming从入门到放弃 —— 第一弹:数字金字塔

寒羽鹿 2022-02-15 阅读 84

动态规划的性质

动态规划常用来解决多阶段决策问题,能用动态规划求解的题目通常需要具有2个特点:
1.最优子结构性质
一个大问题可以分解为若干小问题,大问题的最优解由小问题的最优解推导而来,小问题的最优解构成大问题的最优解
2.无后效性
一旦当前的状态确定,那么它的最优解就确定了,后续就不用关心它是怎样来的,之后大问题就只需调用它的值就可以
在这里插入图片描述

如何设计

  • 设计动态规划需要准备的:
    1、设计状态
    2、设计状态转移方程

  • 设计动态规划方法:
    1、递推(顺推 + 逆推)
    2、记忆化搜索(递归,易超时)

记忆化搜索

记忆化搜索本质上就是DP,只不过它是用递归(DFS)去实现的DP,在DFS的过程中,记忆化消除了重叠子问题
对于数字金字塔:
1、设计状态
Dfs(x,y)表示从(x,y)出发到终点的最大路径和。那么Dfs(1,1)就是我们所求的结果
2、设计状态转移方程

Dfs(x,y) = a[x][y] + max(Dfs(x + 1,y) , Dfs(x + 1,y + 1));

(x,y)到终点的最大路径和可以转换为,从(x,y)的左下角或者右下角到终点的最大路径和
3、记忆化
直接搜索会带来重叠子问题,使得问题复杂度过高,为指数级。所以可以用f[x][y](x,y)到终点的最大路径和保存起来,下次只需要直接调用即可。

例题1 数字金字塔

在这里插入图片描述
问题描述

思路一:贪心
每次选取当前数字最大的路径
在这里插入图片描述
如上图,13 + 11 + 12 + 14 + 13 = 63

贪心策略是否正确?
在这里插入图片描述
13 + 8 + 26 + 15 + 24 = 86,故贪心策略错误

思路二:搜索

dfs(x,y)//从(x,y)开始搜索
{
    return a[x][y] + max(dfs(x + 1,y),dfs(x + 1,y + 1));
}

思路三:记忆化搜索

首先将金字塔存入二维数组之中
在这里插入图片描述

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int n;
const int N = 110;
int a[N][N];//用来存储金字塔
int f[N][N];//f[x][y]用来表示(x,y)到最底层的最大距离

int dfs(int x,int y)//dfs(5,1) = 12
{
    if (f[x][y] != -1) return f[x][y];//只要f[x][y]更新过就可以直接取值
    if (x == n) f[x][y] = a[x][y];
    else f[x][y] = a[x][y] + max(dfs(x + 1,y),dfs(x + 1,y + 1));
    return f[x][y];
}

int main()
{
    cin >> n;
    for (int i = 1;i <= n;i++)//枚举行
        for (int j = 1;j <= i;j++)//是第几行就有几列
            scanf("%d",&a[i][j]);
    memset(f,-1,sizeof f);//将f数组初始化为-1
    dfs(1,1);//从(1,1)开始搜索到底部的最大距离
    cout << f[1][1];
    return 0;
}

思路四:DP(顺推法)

思路五:DP(逆推法)

课后作业 POJ 1163

举报

相关推荐

0 条评论