当前位置: 首页 > news >正文

【C++刷题】优选算法——动态规划第一辑

1.状态表示
	是什么?简答理解是dp表里的值所表示的含义
	怎么来的?
		题目要求
		经验+题目要求
		分析问题的过程中,发现重复子问题
2.状态转移方程
	dp[i]=......

细节问题:
	3.初始化
		控制填表的时候不越界
	4.填表顺序
		控制在填写当前状态的时候,所需要的状态已经填写好了
	5.返回值
		题目要求+状态表示

空间优化
	滚动数组
  1. 第 N 个泰波那契数
int tribonacci(int n)
{
    // 处理一些边界情况
    if(n < 3)
    {
        if(n == 0) return 0;
        else return 1;
    }

    // 1.创建dp表
    vector<int> dp(n + 1);
    // 2.初始化
    dp[0] = 0, dp[1] = 1, dp[2] = 1;
    for(int i = 3; i <= n; ++i)
    {
        // 3.填表
        dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
    }
    // 4.返回值
    return dp[n];
}
// 空间优化版本
int tribonacci(int n)
{
    int arr[3] = { 0,1,1 };
    if(n < 3) return arr[n];

    int ret = 0;
    for(int i = 3; i <= n; ++i)
    {
        ret = arr[0] + arr[1] + arr[2];
        arr[0] = arr[1], arr[1] = arr[2], arr[2] = ret;
    }
    return ret;
}
  1. 三步问题
状态表示:
	经验+题目要求:以i位置为结尾来入手
	dp[i]: 表示到达i位置,一共有多少种方法
状态转移方程:
	基于i位置状态,跨一步到i位置,来划分问题
int waysToStep(int n)
{
    if(1 == n) return 1;
    else if(2 == n) return 2;
    else if(3 == n) return 4;

    // 1.dp数组
    vector<int> dp(n + 1);
    // 2.初始化
    dp[1] = 1, dp[2] = 2, dp[3] = 4;
    for(int i = 4; i <= n; ++i)
    {
        // 3.状态方程
        dp[i] = ((dp[i - 1] + dp[i - 2]) % 1000000007 + dp[i - 3]) % 1000000007;
    }
    // 4.返回值
    return dp[n];
}
  1. 使用最小花费爬楼梯
状态表示:
	经验+题目要求:以i位置为结尾来入手
	dp[i]: 表示i位置到下一步的最小花费
状态转移方程:
	dp[i] = min(dp[i-1], dp[i-2]) + cost[i]
int minCostClimbingStairs(vector<int>& cost)
{
    // 1.dp数组
    vector<int> dp(cost.size());
    // 2.初始化
    dp[0] = cost[0]; dp[1] = cost[1];
    for (int i = 2; i < dp.size(); ++i)
    {
        // 3.状态转移方程
        dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
    }
    // 4.返回值
    return min(dp[dp.size() - 1], dp[dp.size() - 2]);
}
  1. 解码方法
状态表示:
	经验+题目要求:以i位置为结尾来入手
	dp[i]: 表示以i位置为结尾时,解码方法的总数
状态转移方程:

在这里插入图片描述

int numDecodings(string s)
{
    // 0.边界情况
    if(s.size() < 2)
    {
        if(s[0] == '0') return 0;
        else return 1;
    }
    // 1.dp数组
    vector<int> dp(s.size(), 0);
    // 2.初始化
    if (s[0] == '0') dp[0] = 0;
    else dp[0] = 1;
    if (s[0] != '0' && s[1] != '0') dp[1] += 1;
    if (10 <= stoi(s.substr(0, 2)) && stoi(s.substr(0, 2)) <= 26) dp[1] += 1;

    for(int i = 2; i < dp.size(); ++i)
    {
        // 3.状态转移方程
        int num1 =0, num2 = 0;
        if(s[i] != '0') num1 = dp[i - 1];
        if(10 <= stoi(s.substr(i - 1, 2)) && stoi(s.substr(i - 1, 2)) <= 26) num2 = dp[i - 2];
        dp[i] = num1 + num2;
    }
    // 4.返回值
    return dp.back();
}
  1. 不同路径
状态表示:
	经验+题目要求:以[i,j]位置为结尾来入手
	dp[i][j]: 表示以[i,j]位置为finish时,从start出发的不同路径数
状态转移方程:
	dp[i][j] = dp[i-1][j] + dp[i][j-1]
int uniquePaths(int m, int n)
{
    // 1.dp数组
    vector<vector<int>> dp(m, vector<int>(n));
    // 2.初始化
    for (int i = 0; i < m; ++i)
    {
        dp[i][0] = 1;
    }
    for (int i = 0; i < n; ++i)
    {
        dp[0][i] = 1;
    }
    // 3.状态转移方程
    for (int row = 1; row < m; ++row)
    {
        for (int col = 1; col < n; ++col)
        {
            dp[row][col] = dp[row - 1][col] + dp[row][col - 1];
        }
    }
    // 4.返回值
    return dp.back().back();
}
  1. 不同路径 II
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)
{
    // 1.dp数组
    int m = obstacleGrid.size();
    int n = obstacleGrid[0].size();
    vector<vector<int>> dp(m, vector<int>(n));
    // 2.初始化
    for(int i = 0; i < m; ++i)
    {
        if(obstacleGrid[i][0] == 1)
            break;
        dp[i][0] = 1;
    }
    for(int i = 0; i < n; ++i)
    {
        if(obstacleGrid[0][i] == 1)
            break;
        dp[0][i] = 1;
    }
    // 3.状态转移方程
    for(int row = 1; row < m; ++row)
    {
        for(int col = 1; col < n; ++col)
        {
            if(obstacleGrid[row][col] == 1)
                continue;
            dp[row][col] = dp[row - 1][col] + dp[row][col - 1];
        }
    }
    // 4.返回值
    return dp.back().back();
}
  1. 珠宝的最高价值
状态表示:
	经验+题目要求:以[i,j]位置为结尾来入手
	dp[i][j]: 表示到达[i,j]位置时所能得到的的最大价值
状态转移方程:
	dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + frame[i][j]
int jewelleryValue(vector<vector<int>>& frame)
{
    // 1.dp数组
    int row = frame.size();
    int col = frame[0].size();
    vector<vector<int>> dp(row, vector<int>(col));

    // 2.初始化
    dp[0][0] = frame[0][0];
    for(int i = 1; i < col; ++i)
    {
        dp[0][i] = dp[0][i - 1] + frame[0][i];
    }
    for(int i = 1; i < row; ++i)
    {
        dp[i][0] = dp[i - 1][0] + frame[i][0];
    }

    // 3.状态转移方程
    for(int i = 1; i < row; ++i)
    {
        for(int j = 1; j < col; ++j)
        {
            dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + frame[i][j];
        }
    }

    // 4.返回值
    return dp.back().back();
}
  1. 下降路径最小和
状态表示:
	经验+题目要求:以[i,j]位置为结尾来入手
	dp[i][j]: 表示到达[i,j]位置时所得到的最小下降路径和
状态转移方程:
	dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i-1][j+1]) + frame[i][j]
    int minFallingPathSum(vector<vector<int>>& matrix)
    {
        // 1.dp数组
        int n = matrix.size();
        vector<vector<int>> dp(n, vector<int>(n));

        // 2.初始化
        for(int i = 0; i < n; ++i)
        {
            dp[0][i] = matrix[0][i];
        }

        // 3.状态转移方程
        for(int i = 1; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(j == 0)
                {
                    dp[i][j] = min(dp[i - 1][j], dp[i - 1][j + 1]) + matrix[i][j];
                }
                else if(j == n - 1)
                {
                    dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1]) + matrix[i][j];
                }
                else
                {
                    dp[i][j] = min(min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i - 1][j + 1]) + matrix[i][j];
                }
            }
        }

        // 4.返回值
        int min_sum = dp[n - 1][0];
        for(int i = 1; i < n; ++i)
        {
            if(dp[n - 1][i] < min_sum) min_sum = dp[n - 1][i];
        }
        return min_sum;
    }
  1. 最小路径和
状态表示:
	经验+题目要求:以[i,j]位置为结尾来入手
	dp[i][j]: 表示到达[i,j]位置时所得到的最小路径和
状态转移方程:
	dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
int minPathSum(vector<vector<int>>& grid)
{
    // 1.dp数组
    int m = grid.size();
    int n = grid[0].size();
    vector<vector<int>> dp(m, vector<int>(n));

    // 2.初始化
    dp[0][0] = grid[0][0];
    for(int i = 1; i < m; ++i)
    {
        dp[i][0] = dp[i - 1][0] + grid[i][0];
    }
    for(int i = 1; i < n; ++i)
    {
        dp[0][i] = dp[0][i - 1] + grid[0][i];
    }

    // 3.状态转移方程
    for(int i = 1; i < m; ++i)
    {
        for(int j = 1; j < n; ++j)
        {
            dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
        }
    }

    // 4.返回值
    return dp.back().back();
}
  1. 地下城游戏
状态表示:
	经验+题目要求:以[i,j]位置为起点来入手
	dp[i][j]: 表示从[i,j]位置出发,到达终点,所需的最低初始健康点数
状态转移方程:
	dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];
	dp[i][j] = max(1, dp[i][j]); // 细节处理,健康点数至少为1才能存活
int calculateMinimumHP(vector<vector<int>>& dungeon)
{
    // 1.dp数组
    int m = dungeon.size();
    int n = dungeon[0].size();
    vector<vector<int>> dp(m, vector<int>(n));

    // 2.初始化
    if(dungeon[m - 1][n - 1] < 0) dp[m - 1][n - 1] = 1 - dungeon[m - 1][n - 1];
    else dp[m - 1][n - 1] = 1;
    for(int i = n - 2; i >= 0; --i)
    {
        dp[m - 1][i] = dp[m - 1][i + 1] - dungeon[m - 1][i];
        dp[m - 1][i] = max(1, dp[m - 1][i]);
    }
    for(int i = m - 2; i >= 0; --i)
    {
        dp[i][n - 1] = dp[i + 1][n - 1] - dungeon[i][n - 1];
        dp[i][n - 1] = max(1, dp[i][n - 1]);
    }

    // 3.状态转移方程
    for(int i = m - 2; i >= 0; --i)
    {
        for(int j = n - 2; j >= 0; --j)
        {
            dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];
            dp[i][j] = max(1, dp[i][j]);
        }
    }

    // 4.返回值
    return dp[0][0];
}

相关文章:

  • 欧科云链做客Google Cloud与WhalerDAO专题论坛,畅谈Web3数据机遇
  • vue常用指令
  • 008:安装Docker
  • Unity2019.2.x 导出apk 安装到安卓Android12+及以上的系统版本 安装出现-108 安装包似乎无效的解决办法
  • 探秘Nutch:揭秘开源搜索引擎的工作原理与无限应用可能(三)
  • 【vue在主页中点击主页面如何弹出一个指定某个页面的窗口】
  • SQLiteC/C++接口详细介绍之sqlite3类(十五)
  • C++ 虚函数表
  • python之自动化(django)
  • 数据库 | Mysql - [binlog]
  • 【LeetCode热题100】148. 排序链表(链表)
  • 门牌制作-蓝桥杯?-Lua 中文代码解题第3题
  • 第八阶段:uni-app小程序 --首页开发(2)
  • 【深度学习目标检测】二十三、基于深度学习的行人检测计数系统-含数据集、GUI和源码(python,yolov8)
  • Spring同时集成JPA与Mybatis
  • 【C++】vector的使用及其模拟实现
  • SpringCloud Gateway 新一代网关
  • 引领人工智能时代的应用安全
  • java售后服务管理系统
  • Golang实现Redis分布式锁(Lua脚本+可重入+自动续期)
  • 美国务卿鲁比奥将前往土耳其参加俄乌会谈
  • 加拿大新政府宣誓就职
  • 上海杨浦:鼓励龙头企业与高校共建创新联合体,最高支持200万元
  • 反制美国钢铝关税!印度拟对美国部分商品征收关税
  • 学者的“好运气”:读本尼迪克特·安德森《椰壳碗外的人生》
  • 朝着解决问题的正确方向迈进——中美经贸高层会谈牵动世界目光