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

【算法】动态规划专题③ ——二维DP python

目录

  • 前置知识
  • 进入正题
  • 趁热打铁
  • 实战演练
  • 小试牛刀
  • 总结


前置知识


【算法】动态规划专题① ——线性DP python


进入正题


三角形最小路径和 https://leetcode.cn/problems/triangle/

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

示例 1:

输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:

在这里插入图片描述

自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

示例 2:

输入:triangle = [[-10]]
输出:-10

提示:

1 <= triangle.length <= 200
triangle[0].length == 1
triangle[i].length == triangle[i - 1].length + 1
-104 <= triangle[i][j] <= 104


思路:

dp[ i i i][ j j j]表示从triangle[ i i i][ j j j]往下走的最小路径和
写出状态转移方程: dp[ i i i][ j j j] = min(dp[ i i i + 1][ j j j], dp[ i i i + 1][ j j j + 1]) + triangle[ i i i][ j j j]即可


题解code:

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        n = len(triangle)
        dp = [[0] * n for _ in range(n)]
        for i in range(n - 1, -1, -1):
            for j in range(i + 1):
                if i == n - 1:
                    dp[i][j] = triangle[i][j]
                else:
                    dp[i][j] = min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j]
        return dp[0][0]


趁热打铁


数字三角形 https://www.lanqiao.cn/problems/1536/learning/?page=1&first_category_id=1&problem_id=1536

一样的题目,仅仅是最小路径和换成了最大路径和,快来AC吧

附上题解:

n = int(input())
a = [[0] * n for _ in range(n)]
for row in range(n):
    a[row] = list(map(int, input().split()))
dp = [[0] * n for _ in range(n)]
for i in range(n - 1, -1, -1):
    for j in range(i + 1):
        if i == n - 1:
            dp[i][j] = a[i][j]
        else:
            dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + a[i][j]
print(dp[0][0])


实战演练


摆花 https://www.lanqiao.cn/problems/389/learning/?page=1&first_category_id=1&problem_id=389

题目描述

小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾客的喜好,小明列出了顾客最喜欢的种花,从1到n标号。
为了在门口展出更多种花,规定第i种花不能超过a[i]盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。

输入描述
第一行包含两个正整数n和m,中间用一个空格隔开。
第二行有n个整数,每两个整数之间用一个空格隔开,依次表示 a1、a2、…an.
其中,0<n≤100,0<m≤100,0≤ai≤100。

输出描述
输出只有一行,一个整数,表示有多少种方案。
注意:方案数可能很多,请输出方案数对1e6+7取模的结果。

输入输出样例:

输入

2 4
3 2

输出

2

思路:

翻译下题目:
给定n种花,第 i i i种花数量不超过ai,需要凑出m盆,求方案数。
定义:dp[ i i i][ j j j]表示 i i i种花,不超过 j j j盆的方案数
答案即为dp[ n n n][ m m m]
总的能选m盆,第i种花选了x盆,则前i-1种花就只能选m-x盆
得出:dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + ··· + dp[i-1][j-a[i]]


题解code:

mod = 10 ** 6 + 7
n, m = map(int, input().split())
a = [0] + list(map(int, input().split()))
dp = [[0] * (m + 1) for _ in range(n + 1)]
dp[0][0] = 1
for i in range(1, n + 1):
    dp[i][0] = 1
    for j in range(1, m + 1):
        # 前i种花摆j盆 = 第i种花摆的盆数 + 前i-1种花摆的盆数
        # dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + ··· + dp[i-1][j-a[i]]
        for k in range(min(a[i], j) + 1):
            dp[i][j] += dp[i - 1][j - k]
            dp[i][j] %= mod
print(dp[n][m])


小试牛刀


选数异或 https://www.lanqiao.cn/problems/3711/learning/?page=1&first_category_id=1&problem_id=3711

问题描述

给定几个正整数a[i],询问你其中有多少个不同子序列进行异或(⊕)运算的值为x?
由于结果很大,你需要对998244353取模。
异或运算:位运算的一种,符号为⊕,1⊕1=0,1⊕0=1,0⊕0=0.
子序列:从初始序列中选出若干个数保持原有顺序的序列。

输入格式
第一行输入两个正整数n,x
第二行输入n个正整数

输出格式
输出选择不同子序列进行异或(⊕)运算的值为x的方案数,对998244353取模。

样例输入

2 0
2 2

样例输出

2

说明
方案有同时选择两个 2 和一个数都不选。

评测数据规模
1≤n≤1e5,0≤a[i]≤63,0≤x≤63

思路:

定义dp[ i i i][ j j j]: 前 i i i个数异或和为 j j j的方案数
dp[ i i i][ j j j] = 前 i i i-1个数的方案数 + 第 i i i个数的方案
对于第 i i i个数,我们考虑选或不选
不选第 i i i个数:dp[ i i i-1][ j j j] , 选:dp[ i i i-1][ j j j ^ a[ i i i]]
得到状态转移方程: dp[ i i i][ j j j] = dp[ i i i - 1][ j j j] + dp[ i i i - 1][ j j j ^ a[ i i i]]
ans即为dp[ n n n][ x x x]

异或运算性质可以点此进入详细讲解

题解code:

mod = 998244353
n, x = map(int, input().split())
a = [0] + list(map(int, input().split()))
dp = [[0] * 64 for _ in range(n + 1)]  # x<=63
dp[0][0] = 1
for i in range(1, n + 1):
    for j in range(64):
        # dp[i][j]:前i个数异或和为j的方案数
        dp[i][j] = dp[i - 1][j] + dp[i - 1][j ^ a[i]]
        # 不选第i个数:dp[i-1][j],选:dp[i-1][j^a[i]]
        dp[i][j] %= mod

print(dp[n][x])


总结


二维动态规划是解决涉及两个维度变化问题的一种动态规划方法。它通常用于处理那些可以通过构建一个二维表格来记录中间结果,从而优化求解过程的问题。


END
如果有更多问题或需要进一步的帮助,可以在评论区留言讨论哦!
如果喜欢的话,请给博主点个关注 谢谢


http://www.kler.cn/a/533572.html

相关文章:

  • 深度探索DeepSeek-R1:AI大模型的本地应用与个人知识库构建
  • 20250205——Windows系统基于ollama的DeepSeek-R1本地安装
  • kubernetes 核心技术-集群安全机制 RBAC
  • 【Linux系统】信号:再谈OS与内核区、信号捕捉、重入函数与 volatile
  • Web - CSS3浮动定位与背景样式
  • Autosar-以太网是怎么运行的?(Davinci配置部分)
  • 【PromptCoder + Bolt.new】Cascade模式自动生成页面和对应的路由
  • 10.单例模式 (Singleton Pattern)
  • 防火墙策略
  • react的antd表格数据回显在form表单中
  • 2024 TCSVT: LS2T2NN
  • 深入解析 Chrome 浏览器的多进程架构:标签页是进程还是线程?(中英双语)
  • 20250205——Windows系统基于ollama的DeepSeek-R1本地安装
  • 备战蓝桥杯-并查集
  • 【力扣】54.螺旋矩阵
  • PyQt6/PySide6 的 QMainWindow 类
  • 数据传输-工作习惯问题
  • CNN的各种知识点(五):平均精度均值(mean Average Precision, mAP)
  • GaussDB安全配置建议
  • 本地安装部署deepseek
  • 使用 Swift 完成FFmpeg音频录制、播放和视频格式转换应用
  • RabbitMQ 从入门到精通:从工作模式到集群部署实战(一)
  • 【OpenCV实战】基于 OpenCV 的多尺度与模板匹配目标跟踪设计与实现
  • 简易C语言矩阵运算库
  • 【C语言】指针详细解读3
  • 激光工控机在自动化领域中有哪些作用?