【算法】动态规划专题⑪ —— 区间DP python

news2025/2/12 12:22:23

目录

  • 引入
  • 进入正题
  • 回归经典
  • 总结


引入


区间动态规划(区间DP)适用于解决涉及区间最优化的经典问题,如石子合并、最长回文子序列等。


进入正题


石子合并 https://www.acwing.com/problem/content/284/

有 N 堆石子排成一排,其编号为 1,2,3,…,N。
每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N堆石子合并成为一堆。
每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,
合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。

例如有 4 堆石子分别为 1 3 5 2, 我们可以先合并 1、2 堆,代价为 4,得到 4 5 2
又合并 1、2 堆,代价为 9,得到 9 2
再合并得到 11,总代价为 4+9+11=24;

如果第二步是先合并 2、3 堆,则代价为 7,得到 4 7
最后一次合并代价为 11,总代价为 4+7+11=22。

问题是:找出一种合理的方法,使总的代价最小,输出最小代价。

输入格式
第一行一个数 N 表示石子的堆数 N。
第二行 N 个数,表示每堆石子的质量(均不超过 1000)。

输出格式
输出一个整数,表示最小代价。

数据范围
1≤N≤300

输入样例:

4
1 3 5 2

输出样例:

22


方法思路

  1. 状态定义:定义 dp[i][j] 表示处理区间 [i, j] 的最优解。
  2. 状态转移:通过枚举区间分割点 k,将问题分解为子区间 [i, k][k+1, j],并合并结果。
  3. 初始化:处理基础情况(如单个元素的区间)。
  4. 计算顺序:按区间长度从小到大处理,确保子问题已解决。

题解code如下:

n = int(input())
a = list(map(int, input().split()))

# 预处理前缀和数组,方便快速计算区间和
pre_sum = [0] * (n + 1)
for i in range(1, n + 1):
    pre_sum[i] = pre_sum[i - 1] + a[i - 1]

dp = [[0] * (n + 1) for _ in range(n + 1)]  # dp[i][j]表示合并i到j堆的最小代价

# 从2开始枚举区间长度
for length in range(2, n + 1):
    for i in range(n - length + 1):
        j = i + length - 1
        dp[i][j] = 10 ** 9
        # 枚举分割点k
        for k in range(i, j):
            dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + pre_sum[j + 1] - pre_sum[i])
print(dp[0][n - 1])

代码解释

  1. 输入处理:读取石子堆数和每堆的石子数量。
  2. 前缀和数组presum 数组用于快速计算区间 [i, j] 的石子总和。
  3. DP数组初始化dp[i][j] 初始化为0,当 i == j 时无需合并。
  4. 区间遍历:外层循环枚举区间长度,内层循环确定区间起点 i 和终点 j
  5. 状态转移:遍历所有可能的分割点 k,计算合并代价并更新最小值。
  6. 输出结果dp[1][n] 表示合并所有石子的最小代价。


回归经典


最长回文子序列

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

示例 1:

输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。

示例 2:

输入:s = “cbbd”
输出:2
解释:一个可能的最长回文子序列为 “bb” 。

提示:

1 <= s.length <= 1000
s 仅由小写英文字母组成

【算法】动态规划专题④ ——LCS(最长公共子序列)+ LPS(最长回文子序列) python

其他做法不多赘述,在此给出区间DP的做法:

  1. 状态定义dp[i][j] 表示字符串 s[i..j] 的最长回文子序列长度。
  2. 初始化:单个字符的回文长度为1。
  3. 状态转移
    • s[i] == s[j],则结果为内部子串长度加2。
    • 否则,取舍去左端或右端后的最大值。
  4. 计算顺序:从后向前遍历,确保 dp[i+1][j-1] 等子问题已计算。

code如下:

class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n = len(s)
        dp = [[0] * n for _ in range(n)]
        # 从后向前遍历,确保子问题先被计算
        for i in range(n - 1, -1, -1):
            dp[i][i] = 1  # 单个字符是长度为1的回文
            for j in range(i + 1, n):
                if s[i] == s[j]:
                    dp[i][j] = dp[i + 1][j - 1] + 2
                else:
                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
        return dp[0][n - 1]


总结


区间动态规划(Interval Dynamic Programming,简称区间DP)是一种特殊的动态规划类型,它主要处理那些可以分解为子问题的优化问题,而这些子问题往往与某个区间有关。

核心思想

  • 划分问题:将原始问题划分为若干个子问题,每个子问题对应于一个区间。
  • 状态表示:通常用二维数组dp[i][j]来表示从第i个元素到第j个元素之间的最优解。
  • 状态转移方程:通过比较不同的分割点k,找到使得dp[i][j]取得最优值的分割方式。即dp[i][j] = min/max(dp[i][k] + dp[k+1][j] + cost) ,这里的cost是根据具体问题定义的合并成本或收益。
  • 初始化:确定基础情况,如dp[i][i],对于一些问题这可能是0或者是一个特定值。
  • 计算顺序:由于区间长度逐渐增大,所以计算时需要先从小区间开始,逐步求解更长区间的值。

实现步骤

  1. 确定状态:决定使用什么样的二维数组来存储子问题的答案。
  2. 写出状态转移方程:这是最关键的部分,需要仔细分析如何利用已知的小规模问题的解来构建更大规模问题的解。
  3. 边界条件处理:考虑最小规模的问题是如何解决的,并正确初始化。
  4. 选择遍历顺序:通常按照区间长度从小到大进行遍历,确保在计算较大区间之前,所有较小的子区间已经被计算过。

掌握区间DP的关键在于理解其核心思想和实现逻辑,并能够灵活应用于各种具体的场景中。


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2296823.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

玩转适配器模式

文章目录 解决方案现实的举例适用场景实现方式适配器模式优缺点优点:缺点:适配器模式可比上一篇的工厂模式好理解多了,工厂模式要具有抽象的思维。这个适配器模式,正如字面意思,就是要去适配某一件物品。 假如你正在开发一款股票市场监测程序, 它会从不同来源下载 XML 格…

腾讯云大数据套件TBDS与阿里云大数据能力产品对比

前言 博主在接触大数据方向研究的时候是在2016年,那时候正是大数据概念非常火热的一个时间段,最著名的Google的3篇论文。Google FS、MapReduce、BigTable,奠定了大数据框架产品的基础。Google文件系统,计算框架和存储框架。往后所有的大数据产品和过程域无一不是在三个模块…

Codeforces Round 1003 (Div. 4)(A~G题题解)

A. Skibidus and Amogu 思路&#xff1a;把字符串最后的us变成i就可以了&#xff0c;水题一个 #include <iostream> #include <string> int main() { int t; std::cin >> t; std::cin.ignore(); while (t--) { std::string W; std::getline(std::c…

ubuntu使用防火墙开放和关闭指定端口

防火墙可以阻止或允许外部对特定端口的访问&#xff0c;Ubuntu 常用的防火墙管理工具是 ufw&#xff08;Uncomplicated Firewall&#xff09; &#xff0c;如果在开发网络通信相关的内容时&#xff0c;要确保所需的端口是打开的&#xff0c;这样可以排除出题出现时的一个问题—…

mysql8.0使用PXC实现高可用

1.什么是 PXC PXC 是一套 MySQL 高可用集群解决方案&#xff0c;与传统的基于主从复制模式的集群架构相比 PXC 最突出特点就是解决了诟病已久的数据复制延迟问题&#xff0c;基本上可以达到实时同步。而且节点与节点之间&#xff0c;他们相互的关系是对等的。PXC 最关注的是数据…

大数据学习之SparkStreaming、PB级百战出行网约车项目一

一.SparkStreaming 163.SparkStreaming概述 Spark Streaming is an extension of the core Spark API that enables scalable, high-throughput, fault-tolerant stream processing of live data streams. Spark Streaming 是核心 Spark API 的扩展&#xff0c;支持实时数据…

Ollama部署DeepSeek(windows or ubuntu)

Ollama(官网是https://ollama.com/)是一个专为在本地机器上便捷部署和运行大型语言模型&#xff08;LLM&#xff09;而设计的开源框架。它简化了大型语言模型的部署过程&#xff0c;提供了轻量级与可扩展的架构&#xff0c;使得研究人员、开发人员和爱好者能够更加方便地在本地…

10.代码生成器-树表

1.导入部门表 2.配置生成信息页面 生成代码即可使用。

Python的那些事第十六篇:Python的网络爬虫技术

基于Python的网络爬虫技术研究与应用 摘要 随着互联网的飞速发展&#xff0c;网络爬虫技术在数据采集、信息挖掘等领域发挥着重要作用。本文详细介绍了Python环境下常用的网络爬虫技术&#xff0c;包括Requests库、BeautifulSoup库以及Scrapy框架。通过对这些工具的使用方法、…

【AIGC】在VSCode中集成 DeepSeek(OPEN AI同理)

在 Visual Studio Code (VSCode) 中集成 AI 编程能力&#xff0c;可以通过安装和配置特定插件来实现。以下是如何通过 Continue 和 Cline 插件集成 DeepSeek&#xff1a; 一、集成 DeepSeek 获取 DeepSeek API 密钥&#xff1a;访问 DeepSeek 官方网站&#xff0c;注册并获取 …

如何下载CentOS镜像文件

文章目录 如何下载CentOS镜像文件 如何下载CentOS镜像文件 直接前往阿里云官网下载即可。 阿里云官网地址&#xff1a;https://www.aliyun.com 进入官网后&#xff0c;鼠标停留在文档与社区位置&#xff0c;找到镜像站&#xff0c;点击进入即可。进入后&#xff0c;我们可以…

开启对话式智能分析新纪元——Wyn商业智能 BI 携手Deepseek 驱动数据分析变革

2月18号&#xff0c;Wyn 商业智能 V8.0Update1 版本将重磅推出对话式智能分析&#xff0c;集成Deepseek R1大模型&#xff0c;通过AI技术的深度融合&#xff0c;致力于打造"会思考的BI系统"&#xff0c;让数据价值触手可及&#xff0c;助力企业实现从数据洞察到决策执…

嵌入式C语言:大小端详解

目录 一、大小端的概念 1.1. 大端序&#xff08;Big-endian&#xff09; 1.2. 小端序&#xff08;Little-endian&#xff09; 二、大小端与硬件体系的关系 2.1. 大小端与处理器架构 2.2. 大小端与网络协议 2.3. 大小端对硬件设计的影响 三、判断系统的大小端方式 3.1.…

Vue事件处理 - 按键修饰符

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue事件处理 - 按键修饰符 目录 按键修饰符 常见修饰符 绑定按键事件 绑定事件 优化回车修饰符 多个按键 直接绑定数字 总结 按键修饰符 常见修饰符 .esc .up .down .left .right . space .ctrl .shift .delete 绑定…

数据中心网络监控

数据中心是全球协作的特定设备网络&#xff0c;用来在internet网络基础设施上传递、加速、展示、计算、存储数据信息。 对于任何利用IT基础设施的企业来说&#xff0c;数据中心都是运营的核心&#xff0c;它本质上为整个业务网络托管业务应用程序和存储空间。数据中心可以是任…

基于Kotlin中Flow扩展重试方法

最近项目中统一采用Kotlin的Flow来重构了网络请求相关代码。 目前的场景是&#xff0c;接口在请求的时候需要一个accessToken值&#xff0c;因为此值会过期或者不存在&#xff0c;需要刷新&#xff0c;因此最终方案是在使用Flow请求的时候先获取accessToken值然后再进行接口请求…

oracle如何查询历史最大进程数?

oracle如何查询历史最大进程数&#xff1f; SQL> desc dba_hist_resource_limitName Null? Type---------------------------------------------------- -------- ------------------------------------SNAP_ID …

利用HTML和css技术编写学校官网页面

目录 一&#xff0c;图例展示 二&#xff0c;代码说明 1&#xff0c;html部分&#xff1a; 【第一张图片】 【第二张图片】 【第三张图片】 2&#xff0c;css部分&#xff1a; 【第一张图片】 【第二张图片】 【第三张图片】 三&#xff0c;程序代码 一&#xff0c;…

Flink KafkaConsumer offset是如何提交的

一、fllink 内部配置 client.id.prefix&#xff0c;指定用于 Kafka Consumer 的客户端 ID 前缀partition.discovery.interval.ms&#xff0c;定义 Kafka Source 检查新分区的时间间隔。 请参阅下面的动态分区检查一节register.consumer.metrics 指定是否在 Flink 中注册 Kafka…

拯救者Y9000P双系统ubuntu22.04安装4070显卡驱动

拯救者Y9000P双系统ubuntu22.04安装4070显卡驱动 1. 前情&#xff1a; 1TB的硬盘&#xff0c;分了120G作ubuntu22.04。/boot: 300MB, / : 40GB, /home: 75G, 其余作swap area。 2. 一开始按这个教程&#xff1a;对我无效 https://blog.csdn.net/Eric_xkk/article/details/1…