在利用动态规划解决的一些实际问题当中,一类是基于区间上进行的,总的来说,这种区间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)

Problem Description
Dire wolves, also known as Dark wolves, are extraordinarily large and powerful wolves. Many, if not all, Dire Wolves appear to originate from Draenor. Dire wolves look like normal wolves, but these creatures are of nearly twice the size. These powerful beasts, 8 - 9 feet long and weighing 600 - 800 pounds, are the most well-known orc mounts. As tall as a man, these great wolves have long tusked jaws that look like they could snap an iron bar. They have burning red eyes. Dire wolves are mottled gray or black in color. Dire wolves thrive in the northern regions of Kalimdor and in Mulgore. Dire wolves are efficient pack hunters that kill anything they catch. They prefer to attack in packs, surrounding and flanking a foe when they can. — Wowpedia, Your wiki guide to the World of Warcra
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[210],b[210];
int dp[210][210];
int main()
{int t,ii,n,i,j,k,l,Min,m;scanf("%d",&t);for (ii=1;ii<=t;ii++){memset(dp,0,sizeof(0));scanf("%d",&n);for (i=1;i<=n;i++)scanf("%d",&a[i]);for (i=1;i<=n;i++)scanf("%d",&b[i]);for (i=1;i<=n;i++){for (j=i;j<=n;j++)dp[i][j]=99999999;}for (l = 0;l <= n;l++)for (i = 1;i < n+1-l;i++){j = i + l;for (k=i;k<=j;k++)dp[i][j] = min(dp[i][j] , dp[i][k-1] + dp[k+1][j] + a[k] + b[i-1] + b[j+1]);}printf("Case #%d: %lld\n",ii,dp[1][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 = 1 <<30;
const int maxn = 1005;
int dp[maxn][maxn][2] , 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 0;else      return sum[r] - sum[l-1];
}
int main()
{int n , v , x , i , j , k , pos , add;while(scanf("%d%d%d",&n,&v,&x) != EOF){for(i  = 1;i <= n;i++)scanf("%d%d",&a[i].x,&a[i].v);n++;a[n].x = x , a[n].v = 0;sort(a+1 , a+n+1,cmp);for(i  =1 ;i<=n;i++)for(j =1 ;j<=n;j++)dp[i][j][0] = dp[i][j][1] =  inf;for(i = 1;i<=n;i++)sum[i] = sum[i-1] + a[i].v;for(i = 1;i<=n;i++)if(a[i].x == x){pos = i;break;}dp[pos][pos][0] = dp[pos][pos][1] = sum[0] = 0;for(i = pos;i>=1;i--){for(j = pos;j<=n;j++){add = f(1,i-1) + f(j+1,n);if(i==j)  continue;dp[i][j][0] = min(dp[i][j][0] , dp[i+1][j][0] + (add+a[i].v)*(a[i+1].x-a[i].x));dp[i][j][0] = min(dp[i][j][0] , dp[i+1][j][1] + (add+a[i].v)*(a[j].x-a[i].x));dp[i][j][1] = min(dp[i][j][1] , dp[i][j-1][1] + (add+a[j].v)*(a[j].x-a[j-1].x));dp[i][j][1] = min(dp[i][j][1] , dp[i][j-1][0] + (add+a[j].v)*(a[j].x-a[i].x));}}printf("%d\n",min(dp[1][n][0] , dp[1][n][1])*v);}
}

转载于:https://www.cnblogs.com/rhythmic/p/5439094.html

动态规划——区间dp相关推荐

  1. 0x53. 动态规划 - 区间DP(习题详解 × 8)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 文章目录 0x53. 动态规划 - 区间DP Problem A. 最优矩阵链乘 Problem B. ...

  2. 动态规划 —— 区间 DP

    [概述] 区间型动态规划,又称为合并类动态规划,是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的区间中哪些元素合并而来有很大的关系. [思想] 区间 DP 实质上就是 ...

  3. [动态规划] 区间DP

    区间DP 石子合并问题 题目链接 https://www.acwing.com/problem/content/description/284/ 状态表示和状态转移 f [ i ] [ j ] f[i ...

  4. Exploring Pyramids【动态规划——区间DP】

    Exploring Pyramids UVALive - 3516 题目传送门 题目大意:给你一个字符串,其代表的是机器人来回走过的路径,机器人总是先走左边再走右边,问有多少种情况. 解决方法:设输入 ...

  5. 动态规划 —— 区间 DP —— 石子合并三讲

    石子合并问题是最经典的 DP 问题,其有如下3种题型: [任意合并] 1.问题: 有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量.求 ...

  6. 【动态规划区间dp】蓝桥2019:最优包含

    字符串 二维dp: dp[ i ][ j ]表示S中前i个字符包含T中前j个字符至少修改S中前i个字符的字符数 如果S[ i ]==T[ j ] ,则不用修改第i个字符,dp[ i ][ j ] = ...

  7. 【动态规划】区间DP - 最优矩阵链乘(另附POJ1651Multiplication Puzzle)

    最优矩阵链乘(动态规划) 一个n∗mn*mn∗m的矩阵由 nnn 行 mmm 列共 n∗mn*mn∗m 排列而成.两个矩阵A和B可以相乘当且仅当A的列数等于B的行数.一个nm的矩阵乘mp的矩阵,运算量 ...

  8. 【动态规划】区间dp: P1063能量项链

    本题和合并石子果子一样,都是枚举最后一次合并的点 [动态规划笔记]区间dp:合并果子_m0_52043808的博客-CSDN博客 区别: 1.需要断环为链 2.每一堆石子变为两个值,这里用结构体实现 ...

  9. 区间类动态规划(dp)

    一.问题引入 给定长为n的序列a[i],每次可以将连续一段回文序列消去,消去后左右两边会接到一起, 求最少消几次能消完整个序列,n≤500.与线性模型不同,这里消去的顺序是任意的,且消完后左右会接起来 ...

最新文章

  1. 关于photoswiper展示时图片自适应的问题
  2. 编写高性能 .NET 代码 第一章:工具介绍 -- Performance Counters(性能计数器)
  3. 审稿人,我想跟您谈谈心
  4. golang 安全的tcp server_Go 语言使用 TCP_NODELAY 控制发包流量
  5. Numbers on the Chessboard(CF-1027B)
  6. android camera2 qcom,lineage编译环境里,编译QCamera2的技术总结
  7. 情态 语态_情绪与情态与对话情感
  8. 如何把电脑的计算机固定在桌面上,如何将Win7便签固定在电脑桌面上?
  9. eclipse启动tomcat内存溢出解决方式
  10. markdownpad2渲染组件出错——Awesomium sdk组件下载
  11. 如何使用IntelliJ IDEA中自带的mvn命令
  12. Obsidian好用的Markdown工具
  13. 七人成团即拼即赚七人拼团模式解析
  14. 操作系统期末大题复习
  15. 2021年度高等院校皇家勋章授勋仪式-乌隆他尼皇家大学
  16. Pyinstaller打包完整python项目 使用虚拟环境的python项目的打包
  17. 华为S9306 如何进行访问控制配置
  18. python缩写月份单词_Python替换月份为英文缩写的实现方法
  19. 基于Python的名片管理系统
  20. 奉劝那些刚参加工作的学弟学妹们:这20个高质量的学习网站越早知道越好(建议收藏)!!

热门文章

  1. 微信小程序开发第四弹
  2. 再见SpringMVC!linuxkafka安装单机集群
  3. 机器学习(MACHINE LEARNING)MATLAB非线性曲线拟合方法
  4. python【力扣LeetCode算法题库】28-实现 strStr()
  5. python【Matlibplot绘图库】-二维图形绘制
  6. 运筹学两阶段法编程c语言,运筹学上机实验 - 单纯形方法的两阶段法
  7. java 类成员访问权限_Java类成员访问权限控制知识总结
  8. htpc电脑方案_我终于定稿了客厅HTPC的方案: Matx机箱小喆B3卧倒
  9. mac系统学习和快捷键
  10. 万词霸屏的本质是什么?