动态规划——区间dp
在利用动态规划解决的一些实际问题当中,一类是基于区间上进行的,总的来说,这种区间dp是属于线性dp的一种。但是我们为了更好的分类,这里仍将其单独拿出进行分析讨论。
让我们结合一个题目开始对区间dp的探讨。
凸多边形的最优三角剖分:给定一个具有N个顶点(N ≤ 50)(顶点从1到N编号)的凸多边形,每个顶点的权均已知。问如何把这个 凸多边形划分成N-2 个互不相交的三角形,使得这些三角形顶点的权的乘积之和最小。
其实有一些组合数学底子的读者对这个模型会非常熟悉,笔者在《组合数学——Catalan数》中探讨Catalan数的时候,其实给出了一个类似的模型。
那么我们先着眼于这个问题,首先依然是dp的惯有套路——子问题化。我们设置二维数组f[i,j]记录以第i个顶点到第j个顶点最优方案(i < j),s[m]记录第m个点的权值。那么此时我们只要设置一个参量k,使得k遍历(i,j)的所有值,便把f[i,j]与其更小的子问题建立起了递推关系,即如下的状态转移方程。
for k (i + 1) to (j - 1)
f[i,j] = f[i,k] + f[k,j] + s[i]*s[j]*s[k].
而显然f[1,n]即是我们最终想要全局问题的解。
让我们来看一道与这个模型很类似的题目。(Problem source : hdu 5115)
Matt, an adventurer from the Eastern Kingdoms, meets a pack of dire wolves. There are N wolves standing in a row (numbered with 1 to N from left to right). Matt has to defeat all of them to survive.
Once Matt defeats a dire wolf, he will take some damage which is equal to the wolf’s current attack. As gregarious beasts, each dire wolf i can increase its adjacent wolves’ attack by bi. Thus, each dire wolf i’s current attack consists of two parts, its basic attack ai and the extra attack provided by the current adjacent wolves. The increase of attack is temporary. Once a wolf is defeated, its adjacent wolves will no longer get extra attack from it. However, these two wolves (if exist) will become adjacent to each other now.
For example, suppose there are 3 dire wolves standing in a row, whose basic attacks ai are (3, 5, 7), respectively. The extra attacks bi they can provide are (8, 2, 0). Thus, the current attacks of them are (5, 13, 9). If Matt defeats the second wolf first, he will get 13 points of damage and the alive wolves’ current attacks become (3, 15).
As an alert and resourceful adventurer, Matt can decide the order of the dire wolves he defeats. Therefore, he wants to know the least damage he has to take to defeat all the wolves.
题目大意:给出n个狼的伤害以及每个狼对相邻狼的伤害加成,杀死第i只狼,遭受对应伤害,该狼对相邻狼的攻击加成消失,第i-1和第i+1只狼成为相邻。求解杀死n只狼所受的最小伤害是多少。
数理分析:我们设置a[i]记录第i只狼的伤害,b[i]记录第i只狼对相邻狼的加成效果。
设置dp[i][j]记录杀死第i只到第j只狼所受的最小伤害(之所以这样设置,是呼应区间dp问题中的子问题化)。那么对于j>i时,我们探讨dp[i][j]与其余状态参量有着怎样的递推关系。
我们做类似凸多边形最优三角剖分的分析,对于k∈[i,j],如果基于两个最优子区间dp[i][k-1] , dp[k+1][j],我们得到的一定是"相对"最优的解,很显然嘛两个子区段的最优一定会引导出整体的"相对"最优,而之所以说相对最优,是因为在k取不同值的时候,我们可以从这些相对最优的解组成的集合中找出一个最优解,那么它便是当前最优,这样便可建立较长区间与较短区间的递推关系,即:
dp[i][j] = min(dp[i][k-1] + dp[k+1][j] + a[k] + b[i-1] + b[j+1])
需要注意的是,基于这种状态转移方程的特点,我们计算的时候需要先以区间的长度为指标,即先求解区间长度较短的子问题,这需要我们在编码时枚举子问题做出相应的调整。
参考代码如下。
#include <iostream>
#include <cstdio>
#include<cstring>
#include <algorithm>
using namespace std;
int a[],b[];
int dp[][];
int main()
{
int t,ii,n,i,j,k,l,Min,m;
scanf("%d",&t);
for (ii=;ii<=t;ii++)
{
memset(dp,,sizeof());
scanf("%d",&n);
for (i=;i<=n;i++)
scanf("%d",&a[i]);
for (i=;i<=n;i++)
scanf("%d",&b[i]); for (i=;i<=n;i++)
{
for (j=i;j<=n;j++)
dp[i][j]=;
} for (l = ;l <= n;l++)
for (i = ;i < n+-l;i++)
{
j = i + l;
for (k=i;k<=j;k++)
dp[i][j] = min(dp[i][j] , dp[i][k-] + dp[k+][j] + a[k] + b[i-] + b[j+]);
}
printf("Case #%d: %lld\n",ii,dp[][n]);
} }
让我们再来看一道区间dp。(Problem source : zoj 3469)
When we are focusing on solving problems, we usually prefer to stay in front of computers rather than go out for lunch. At this time, we may call for food delivery.
Suppose there are N people living in a straight street that is just lies on an X-coordinate axis. The ith person's coordinate is Xi meters. And in the street there is a take-out restaurant which has coordinates X meters. One day at lunchtime, each person takes an order from the restaurant at the same time. As a worker in the restaurant, you need to start from the restaurant, send food to the N people, and then come back to the restaurant. Your speed is V-1 meters per minute.
You know that the N people have different personal characters; therefore they have different feeling on the time their food arrives. Their feelings are measured by Displeasure Index. At the beginning, the Displeasure Index for each person is 0. When waiting for the food, the ith person will gain Bi Displeasure Index per minute.
If one's Displeasure Index goes too high, he will not buy your food any more. So you need to keep the sum of all people's Displeasure Index as low as possible in order to maximize your income. Your task is to find the minimal sum of Displeasure Index.
Input
The input contains multiple test cases, separated with a blank line. Each case is started with three integers N ( 1 <= N <= 1000 ), V ( V > 0), X ( X >= 0 ), then N lines followed. Each line contains two integers Xi ( Xi >= 0 ), Bi ( Bi >= 0), which are described above.
You can safely assume that all numbers in the input and output will be less than 231 - 1.
Please process to the end-of-file.
Output
For each test case please output a single number, which is the minimal sum of Displeasure Index. One test case per line.
题目大意:给出一个快递员在数轴上的坐标x,其速度的倒数v,以及需要送货的门户数n,然后给出n户人家在x轴上的坐标以及单位时间不满意度的增幅,请求解该快递员送完n户后最小的不满意度。
数理分析:首先我们将这n+1个位置进行排序,基于最简单的贪心策略,快递员应该送离其最近的人家。即排序后从x处往左或者往右挨个送,而到底往左还是往右,便要进行动态规划的分析了。
子问题化:我们容易看到问题的参数可以放到一个区间[i,j]上,而我们应该注意到对于一个子问题dp[]i[j]来表征快递员送完[i,j]上的人家的最小不满意度,快递员的最终位置是在i还是在j上是表达不同的含义的(这在后面寻求状态转移方程的时候就会发现),因此这里对于最优解的记录,我们有三个维度,即dp[i][j][0]表示区间[i,j]上并以i作为终点的最优解。dp[i][j][1]则表示以j作为终点。
寻求状态转移方程:模拟求解dp[i][j],我们需要分成两种情况。我们设置v[i]记录第i家单位时间不满意度的增幅,x[i]为第i家在数轴上的坐标。
①dp[i][j][0]:这种情况的终点是i,显然,经过i必然经过i-1,因此这里我们对于dp[i][j][0]的求解,需要基于dp[i-1][j][0]、d[i-1][j][1]这两个与其关系最紧密子问题(这里寻求递推关系找当前情况的子问题非常重要,即通过模拟过程找出当前情况前一步必须进行的过程,从而能够建立起状态转移方程)。
那么基于两个最紧密的子问题,我们很容易找到状态转移方程了。
dp[i][j][0] = min(dp[i-1][j][0] + dis(i-1 to i)*(add + v[i])*v , dp[i-1][j][1] + dis(i to j)*(add + v[i])*v)。
同理,对于dp[i][j][1]的求解,可做对称分析。
那么基于这一半的状态转移方程,dis(i to j)表示i到j的距离,add表示总区间上出去[i,j]上的点单位时间不满意度的增幅,v是速度的倒数,那么方程的物理含义就不难理解了。
值得注意的一点是,这道题目在状态转移的过程中每次*v可能会造成数据的溢出,这里采用的技巧是假设v =1,那么状态转移方程可以去掉*v部分,然后基于最终的结果,再乘以v即可。
参考代码如下。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int inf = <<;
const int maxn = ;
int dp[maxn][maxn][] , sum[maxn]; struct node
{
int x , v;
}a[maxn];
bool cmp(node a , node b)
{
return a.x < b.x;
}
int f(int l , int r)
{
if(l > r) return ;
else return sum[r] - sum[l-];
}
int main()
{
int n , v , x , i , j , k , pos , add;
while(scanf("%d%d%d",&n,&v,&x) != EOF)
{
for(i = ;i <= n;i++)
scanf("%d%d",&a[i].x,&a[i].v);
n++;
a[n].x = x , a[n].v = ;
sort(a+ , a+n+,cmp);
for(i = ;i<=n;i++)
for(j = ;j<=n;j++)
dp[i][j][] = dp[i][j][] = inf; for(i = ;i<=n;i++)
sum[i] = sum[i-] + a[i].v; for(i = ;i<=n;i++)
if(a[i].x == x)
{
pos = i;
break;
}
dp[pos][pos][] = dp[pos][pos][] = sum[] = ;
for(i = pos;i>=;i--)
{
for(j = pos;j<=n;j++)
{
add = f(,i-) + f(j+,n);
if(i==j) continue;
dp[i][j][] = min(dp[i][j][] , dp[i+][j][] + (add+a[i].v)*(a[i+].x-a[i].x));
dp[i][j][] = min(dp[i][j][] , dp[i+][j][] + (add+a[i].v)*(a[j].x-a[i].x));
dp[i][j][] = min(dp[i][j][] , dp[i][j-][] + (add+a[j].v)*(a[j].x-a[j-].x));
dp[i][j][] = min(dp[i][j][] , dp[i][j-][] + (add+a[j].v)*(a[j].x-a[i].x));
}
} printf("%d\n",min(dp[][n][] , dp[][n][])*v); }
}
动态规划——区间dp的更多相关文章
- 动态规划——区间DP,计数类DP,数位统计DP
本博客部分内容参考:<算法竞赛进阶指南> 一.区间DP 划重点: 以前所学过的线性DP一般从初始状态开始,沿着阶段的扩张向某个方向递推,直至计算出目标状态. 区间DP也属于线性DP的一种, ...
- 模板 - 动态规划 - 区间dp
因为昨天在Codeforces上设计的区间dp错了(错过了上紫的机会),觉得很难受.看看学长好像也有学,就不用看别的神犇的了. 区间dp处理环的时候可以把序列延长一倍. 下面是 $O(n^3)$ 的朴 ...
- 动态规划---区间dp
今天写内网题,连着写了两道区间dp,这里就总结一下. 区间dp思想主要是先枚举f[i][j]中的i,再枚举j,再枚举一个1~j之间的变量k,一般是f[i][j] = max(f[i][j],f[i][ ...
- [hdu contest 2019-07-29] Azshara's deep sea 计算几何 动态规划 区间dp 凸包 graham扫描法
今天hdu的比赛的第一题,凸包+区间dp. 给出n个点m个圆,n<400,m<100,要求找出凸包然后给凸包上的点连线,连线的两个点不能(在凸包上)相邻,连线不能与圆相交或相切,连线不能相 ...
- Hdu OJ 5115 Dire Wolf (2014ACM/ICPC亚洲区北京站) (动态规划-区间dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5115 题目大意:前面有n头狼并列排成一排, 每一头狼都有两个属性--基础攻击力和buff加成, 每一头 ...
- Light OJ 1025 - The Specials Menu(动态规划-区间dp)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1025 题目大意:一串字符, 通过删除其中一些字符, 能够使这串字符变成回文串. ...
- [SCOI2007]压缩(动态规划,区间dp,字符串哈希)
[SCOI2007]压缩 状态:设\(dp[i][j]\)表示前i个字符,最后一个\(M\)放置在\(j\)位置之后的最短字串长度. 转移有三类,用刷表法来实现. 第一种是直接往压缩串后面填字符,这样 ...
- [jdoj1090]矩阵_区间dp
矩阵 jdoj-1910 题目大意:给你连续的n个矩阵的长和宽,保证每连续的两个相邻矩阵满足相乘的条件,不能改变题目中矩阵的位置,求将这些矩阵相乘为一个矩阵的最小乘法次数. 注释:1<=n< ...
- 动态规划(区间DP):HDU 5115 Dire Wolf
Dire wolves, also known as Dark wolves, are extraordinarily large and powerful wolves. Many, if not ...
随机推荐
- jquery 操作 checkbox
对checkbox的其他几个操作 1. 全选2. 取消全选3. 选中所有奇数4. 反选5. 获得选中的所有值 js代码 $("document").ready(function() ...
- xcode7 icon图标设置
- 使用SQL Server 2008远程链接时SQL数据库不成功的解决方法
关键设置: 第一步(SQL2005.SQL2008): 开始-->程序-->Microsoft SQL Server 2008(或2005)-->配置工具-->SQL Serv ...
- javascript——迭代方法
<script type="text/javascript"> //五个迭代方法 都接受两个参数:要在每一项上运行的函数 和 运行该函数的作用域(可选) //every ...
- TestNG扩展
1. TestNG API 本章节将讨论如何使用TestNG API来创建自己的TestNG对象.TestNG的API基本由接口组成,这样做是为了容易模拟TestNG返回的对象. 1.1 org.te ...
- 关于this
一:全局环境中的this指的是window对象 二:作为对象的方法调用 当函数作为对象的方法被调用时,this指向该对象 例子: 三:作为普通方法调用 当函数不作为对象的属性被调用,而是作为普通函数函 ...
- 根据打开页面加载不同Js
根据打开页面加载不同Js //根据打开页面加载不同JS $(document).ready(function(){ var href = document.URL; /*获取当前页面的URL*/ if ...
- PHP第一课笔记
打算以后学习PHP,花3个月时间学会它,自己为自己加油.每天坚持学习,第一天感觉良好,没开始写,所以不敢觉难,在难也学,加油,me!! PHP笔记记录(2014.7.27) ★web开发的介绍 1.动 ...
- HashMap在Android和Java中的不同实现
起因 今天在项目中遇到一个很"奇葩"的问题.情况大致是这样的:Android终端和服务器(Spring),完全相同的字符串键值对放入HashMap中竟然顺序不一样,这直接导致了服务 ...
- 如何将BarTender内容锁定不让改动
条码标签代表的是产品的特性等,具有相当的精确性,所以需要保证它的正确性.而使用BarTender软件,可以帮助小伙伴将设计的条码标签内容锁定,保护它而不被人改动.下面,小编就教教大家如何实现BarTe ...