区间DP(多类石子合并问题)

区间DP(石子合并I,石子合并II,石子合并II改良,式子合并1进阶)

石子合并I

设有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

我的代码不小心删掉了,所以在ACwing上找了1楼大佬Taozex的代码
具体解法都是一样

三层循环,f[i][j]表示合并第i个石子到第j个石子的代价最小

先memset,将f区间里的所有数置无限大(因为我们要取最小值,如果我们置为0的话,任意区间最小值都会是0),然后套一层循环,输入每个石子的代价

为何f[i][i]要置为0呢,因为这个表示我们把第i个石子和第i个石子合并,可是我们就只有一个石子,根本不需要合并,所以代价为0(这里不用担心会把最小值置为0,因为后面三层循环那有s[r]-s[r-1],所以不会,那为何我们要置其他值无穷大呢,因为三层循环那有个min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]),如果置于0,那么f[l][r]会等于0,min也会一直取0),其他的我们没算,所以代价无穷大。

下面是三层循环,这是区间DP常用循环,我们要取区间1-n的最小值,我们得先了解区间1到n-1的最小值,以及2到n的最小值,依次类推,我们要知道任何区间大小的最小值。

len表示我们要取的区间的长度,比如len=2,表示我们的取得石子数为2,由2到n进行循环,表面我们先算长度为2的区间的合并石子方法,依次类推

下面是for对i的循环,r表示我们取得那个区间的最后一个石子,比如len=3时,i=1,那么r=3,i=2,r就等于4,i=50,r就等于53.等等

最后对k循环,这个是精髓,我们不妨想一下有10堆石子,我们任意合并2堆石子,到最后第二步,是不是还剩下2堆石子要合并,因为我们是合并相邻的两堆,那么最后2堆中的石子,记为a,b,那么a中的每一堆合并的石子都没和b中的合并,那么我们可以用k把他们分开,k=1,表示将石子从第一堆和第2-10堆分开求,k=2,,表示将石子从第1-2堆和第3-10堆的最优解等等

下面是代码

在这里插入图片描述

合并石子II

在这里插入图片描述

从一排变为了一圈,建议先把合并石子I弄完,再看

首先,我们分析一下题目的变化,就是一排变为了一圈,那么对应着我们的最小区间有什么变化呢?

仔细想一想,如果有10个石子,如果是1排的话,那么石子1,和石子10不会合并,但是再一圈中,就会合并,所以对于这一类问题,我们的方法是将环切为线

那么切为线之后,不是和合并石子I一样了吗,那怎么做,表示能和合并石子II等价呢

这个就是把从n堆石子推到2n-1堆石子,其中后面n-1堆石子就是前面n-1堆石子,假设一共10堆石子,我们取区间10,我们把环换为线后,就一共有19堆石子,但是我们最多只能取10堆相邻石子。
所以我们在想为什么这里取10堆可以解决环形问题呢,首先环形合并和线性合并有个类似地方,那就是我们在最后第二步合并时,取第一堆为a,第二堆为b,那么a堆的石子肯定在ab合并前没有和b堆里的石子合并过,加入a堆是1-4,b堆是5-10,那么4和5肯定没合并过,所以我们沿这条线分开,分别解决子问题1-4的最小代价和5-10的最小代价,那么环也类似,到最后如果a堆为10到1到4,b堆为5-9,那么我们可以将4和5分开,但是因为10和1它们合并了,我们合并石子区间不能是1-10了,这个等价于我们合并第10堆到第10+10-1堆的石子。

同理,如果a堆为8到1到4,那么b堆是5到7,我们可以相当于将第8堆到第8+10-1堆合并
a堆为6-9堆,b堆为10到1到5堆,那么相当于第6堆到第6+10-1堆合并

掌握思想就容易算了,我这边sum表示前缀和
在这里插入图片描述

合并石子优化

首先,我们要知道这是o(n^3)的复杂度,数据只能在250以下,一旦超过就会超时,那么我们要优化三重循环,因为i,j是对于所有区间的枚举,所以改不了,那么我们优化k

这是我们用到平行四边形不等式

假如给你a,b,c,d四个数
a<b<=c<d
那么要有f[a][c]+f[b][d]<=f[a][d]+f[b][c]

这个证明,读者还是另寻高就,我整了半天没整明白

但是主要证明思路,是证明我上面代码三重循环里sum[j]-sum[i-1]满足这个不等式
还有就是dp[i][k-1]+dp[k][j]满足不等式,之后得到整体满足不等式后,再得到最优解满足下面的式子。

但是,这些都不重要,因为我们比赛的时候没多少时间去推理,所以,我们最好的办法就是写代码打表,观察最优解是否又递增趋势,如果有,那么我们用这个,没有就不用

在本题中,我们选s[i][j]表示区间i-j的最优解,
那么s[i][j-1]<=s[i][j]<=s[i+1][j]
这表明我们最优策略是递增的,即i到j-1的最优策略的位置一定小于等于i到j的最优策略位置

这个也只对最小值有效,对最大值无效

优化代码就是先声明一个s[i][j]表面最优解,初始化s[i][i]=i,不初始化为0或者其他值,因为后面第3重循环k是取s[i][j-1]到s[i+1][j]的,取其他值,在刚开始循环时就会出错

在这里插入图片描述

改良后的循环。

石子合并I进阶

这个进阶真不是人能想出来的。

题目和1是一样的,但是细节改变了,那就是输入数据可以有40000了,这个表示着以前的区间DP没有一点用了,这个用到了数学知识,我还没了解
在这里插入图片描述
在这里插入图片描述
这是以为AC的人写的例子,很形象的概括了这个算法。
这个是代码,那个头文件得改为万能头文件,不然getchar不能过,而且得开启O2优化,因为vector的删改速度慢
在这里插入图片描述

以上就是合并石子的所有例题了,掌握了这个,区间DP也算入门了,后面就要接着字符串什么的了,加油吧。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值