区间dp(动态规划)

这篇具有很好参考价值的文章主要介绍了区间dp(动态规划)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

区间dp(动态规划),C++专栏,动态规划,算法

什么是动态规划

动态规划(dp)是一种通过将问题分解为子问题,并利用已解决的子问题的解来求解原问题的方法。适用于具有重叠子问题和最优子结构性质的优化问题。通过定义状态和状态转移方程,动态规划可以在避免重复计算的同时找到问题的最优解,是一种高效的求解方法,常用于解决各种问题,如最短路径、背包问题、序列比对等。


区间dp

区间dp(动态规划),C++专栏,动态规划,算法

定义

区间dp是一种dp的应用,用于解决涉及区间的问题。
它将问题划分为若干个子区间,并通过定义状态和状态转移方程来求解每个子区间的最优解,最终得到整个区间的最优解。


应用

区间动态规划常用于解决一些涉及区间操作的问题,如最长公共子序列、最长回文子串等。在区间动态规划中,通常需要定义一个二维数组来表示子区间的状态,并通过填表的方式逐步求解子区间的最优解,最后得到整个区间的最优解。区间动态规划是一种高效的求解方法,可以有效地解决各种区间问题。



例题引入

石子合并是一道非常经典的区间DP的例题,很适合新手练习,下面我们看看这个题目:

题目描述

在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N N N 堆石子合并成 1 1 1 堆的最小得分和最大得分。

输入格式

数据的第 1 1 1 行是正整数 N N N,表示有 N N N 堆石子。

2 2 2 行有 N N N 个整数,第 i i i 个整数 a i a_i ai 表示第 i i i 堆石子的个数。

输出格式

输出共 2 2 2 行,第 1 1 1 行为最小得分,第 2 2 2 行为最大得分。

样例

样例输入

4
4 5 9 4

样例输出

43
54

提示

1 ≤ N ≤ 100 1\leq N\leq 100 1N100 0 ≤ a i ≤ 20 0\leq a_i\leq 20 0ai20



贪心法

稍微想想就知道不可行,因为它每次只能合并相邻的两堆石子,用贪心的话会答案错误,因此我们考虑区间dp。


区间dp

利用区间动态规划来解决此类问题。

优缺点:

优点 缺点
可以求出正解 时间复杂度高
代码量相对较少 效率低
容易理解 数据量大会超时

确实,此题的时间复杂度高达 O ( 2 n 3 ) O(2n^3) O(2n3),若非这道题的数据量极小,下面的代码便会超时,那么就需要用一个特殊方法来优化一下。

AC代码:

#include <bits/stdc++.h>
using namespace std;
int n,ans1=0x7fffffff,ans2,a[300],sum[300];
int mi[300][300],ma[300][300];
int main() {
	cin >>n;
	for (int i=1; i<=n; i++) {
		cin >>a[i];
		a[i+n]=a[i];
	}
	for (int i=1; i<=2*n; i++)
		sum[i]=sum[i-1]+a[i];
	memset(mi,0x3f,sizeof(mi));
	for (int i=1; i<=2*n; i++)
		mi[i][i]=0;
	for (int l=1; l<n; l++) {
		for (int i=1; i+l<=2*n; i++) {
			for (int j=i; j<i+l; j++) {
				mi[i][i+l]=min(mi[i][i+l],mi[i][j]+mi[k+1][i+l]+sum[i+l]-sum[i-1]);
				ma[i][i+l]=max(ma[i][i+l],ma[i][j]+ma[k+1][i+l]+sum[i+l]-sum[i-1]);
			}
		}
	}
	for (int i=1; i<n; i++)
		ans1=min(ans1,mi[i][i+n-1]);
	for (int i=1; i<n; i++)
		ans2=max(ans2,ma[i][i+n-1]);
	cout <<ans1 <<endl <<ans2;
	return 0;
}

代码详解

三层for循环

  • 第一层for循环用来分区间,我们可以选择将一个大区间分成若干个小区间,那么分的标准是什么呢?这就是第一层for循环的作用, l l l就是每次分的区间长度。
  • 第二层循环就是定义区间的左端点, j = 1 j=1 j=1,再根据 l = 2 l=2 l=2,就能确定区间为 ( 1 , 2 ) (1,2) (1,2),即 f [ 1 ] [ 2 ] f[1][2] f[1][2]
  • 然后第三层循环就是拆分了,如上图, l = 2 l=2 l=2的时候是无法拆分了,但是 l = 3 l=3 l=3的时候是可以拆成 f [ 1 ] [ 2 ] , f [ 3 ] [ 3 ] , f [ 1 ] [ 1 ] , f [ 2 ] [ 3 ] f[1][2],f[3][3],f[1][1],f[2][3] f[1][2],f[3][3],f[1][1],f[2][3],以及各个数据都有或没有拆分方法。

状态转移方程

区间拆分了,那么我们如何去算转移方程呢?我们将两个区间 ( 1 , 2 ) (1,2) (1,2) ( 3 , 4 ) (3,4) (3,4)进行合并,那么就是1,2的代价加上3,4的代价,再加上1到4的区间和,具体的式子如下

f[1][4] = min(f[1][4],f[1][2]+f[3][4]+s[4]-s[0]);

为什么这么计算呢,因为你要知道你在求解的过程中是通过小的区间组合成较大的区间的,而你所用到的这两个小的区间 f [ 1 ] [ 2 ] + f [ 3 ] [ 4 ] f[1][2]+f[3][4] f[1][2]+f[3][4],已经得出了最优解了,那么得出最优解需不需要花费代价呢?当然需要,所以我们需要加上那段花费,那么简单来说就是

f[1][2]+f[3][4]=s[2]-s[0]+s[4]-s[2]

因此,状态转移方程便有了:

f[i][i+l]=min(f[i][i+l],f[i][k]+f[k+1][i+l]+s[i+l]-s[i-1]);

环形的处理

我们仔细阅读题目即可发现:石子是按照环形摆放的,因此区间的头和尾是能够合并的,那么如何处理呢?
方法很简单,只需要将整一条线性的石头复制一个,让第二个的头对着第一个的尾,然后正常处理即可。
这一点在程序的很多地方可以体现出来,如:

	for (int i=1; i<=n; i++) {
		cin >>a[i];
		a[i+n]=a[i];
	}

	for (int i=1; i<=2*n; i++)

以及

	for (int i=1; i+l<=2*n; i++)

等等。文章来源地址https://www.toymoban.com/news/detail-558558.html

到了这里,关于区间dp(动态规划)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 动态规划——区间dp [石子合并]

    动态规划——区间dp [石子合并]

    动态规划(dp)是一种通过将问题分解为子问题,并利用已解决的子问题的解来求解原问题的方法。适用于具有重叠子问题和最优子结构性质的优化问题。通过定义状态和状态转移方程,动态规划可以在避免重复计算的同时找到问题的最优解,是一种高效的求解方法,常用于

    2024年02月12日
    浏览(10)
  • 动态规划系列 | 一文搞定区间DP

    动态规划系列 | 一文搞定区间DP

    区间 DP 可以用于解决一些涉及到区间合并或分割的问题。区间 DP 通常有以下三个特点: 合并(分割) :将两个或多个部分进行整合,或者反过来将一个区间分解成多个部分。 特征 :能将问题分解为能两两合并的形式。 求解 :对整个问题设最优解,枚举合并点,将问题分

    2024年02月02日
    浏览(11)
  • 石子合并(动态规划 区间DP)+详细注释

    原题链接   活动 - AcWing 题目 设有 N 堆石子排成一排,其编号为 1,2,3,…,N。 每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。 每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相

    2024年02月16日
    浏览(9)
  • 【动态规划】LeetCode 312. 戳气球 --区间DP问题

    【动态规划】LeetCode 312. 戳气球 --区间DP问题

      Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法......感兴趣就关注我吧!你定不会失望。 🌈个人主页:主页链接 🌈算法专栏:专栏链接       我会一直往里填充内容哒! 🌈LeetCode专栏:专栏链接       目前在刷初级算法的LeetBook 。若每日一题当中有力所能

    2023年04月16日
    浏览(10)
  • 蓝桥杯备赛之动态规划篇——涂色问题(区间DP)

    蓝桥杯备赛之动态规划篇——涂色问题(区间DP)

    2023第十四届蓝桥杯模拟赛第二期个人题解(Java实现) 2023第十四届蓝桥杯模拟赛第三期个人题解(Java实现) 蓝桥杯备赛之动态规划篇——背包问题 蓝桥杯真题——单词分析(Java实现) 😘😘 哈喽,大家好!这里是蓝桥杯系列文章的动态规划章节🔥🔥,今天要讲解的是区

    2024年01月23日
    浏览(15)
  • 【动态规划专栏】专题三:简单多状态dp--------3.删除并获得点数

    【动态规划专栏】专题三:简单多状态dp--------3.删除并获得点数

    本专栏内容为:算法学习专栏,分为优选算法专栏,贪心算法专栏,动态规划专栏以及递归,搜索与回溯算法专栏四部分。 通过本专栏的深入学习,你可以了解并掌握算法。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:动态规划专栏 🚚代码仓库:小小unicorn的代码仓库🚚

    2024年03月22日
    浏览(7)
  • 【动态规划 区间dp 位运算】100259. 划分数组得到最小的值之和

    【动态规划 区间dp 位运算】100259. 划分数组得到最小的值之和

    动态规划 区间dp 位运算 给你两个数组 nums 和 andValues,长度分别为 n 和 m。 数组的 值 等于该数组的 最后一个 元素。 你需要将 nums 划分为 m 个 不相交的连续 子数组,对于第 ith 个子数组 [li, ri],子数组元素的按位AND运算结果等于 andValues[i],换句话说,对所有的 1 = i = m,n

    2024年04月15日
    浏览(11)
  • 【LeetCode每日一题: 1039. 多边形三角剖分的最低得分 | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】

    【LeetCode每日一题: 1039. 多边形三角剖分的最低得分 | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】

    🍎作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎 🍎座右铭:人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?🎯🎯🎯 1039. 多边形三角剖分的最

    2023年04月19日
    浏览(8)
  • DP算法:动态规划算法

    DP算法:动态规划算法

    (1)确定初始状态 (2)确定转移矩阵,得到每个阶段的状态,由上一阶段推到出来 (3)确定边界条件。 蓝桥杯——印章(python实现) 使用dp记录状态,dp[i][j]表示买i张印章,凑齐j种印章的概率 i表示买的印章数,j表示凑齐的印章种数 情况一:如果ij,不可能凑齐印章,概

    2024年02月07日
    浏览(7)
  • 算法——动态规划(DP)——递推

    算法——动态规划(DP)——递推

    动态规划常用于解决优化问题。 动态规划通常以自底向上或自顶向下的方式进行求解。 自底向上的动态规划从最简单的子问题开始,逐步解决更复杂的问题,直到达到原始问题。 自顶向下的动态规划则从原始问题出发,分解成子问题,并逐步求解这些子问题。 动态规划算法

    2024年01月20日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包