区间DP(总结)
学长一晚上的耐心讲解,使我明白区间DP这么高级的东西,还是挺容易的。也就是在一段区间内的动态规划。
下面用例题进行总结。
例题:石子归并。
描述 有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,并将新的一堆石子数记为该次合并的得分。
给组测试数据
输入 4 表示有4堆石子
4 4 5 9 表示每堆石子的个数
输出 54 表示最大的得分
分析:主要思想就是一个一个累加:4 4 5 9 先看下去是我想知道dp[i][j]的最大值,i表示起始位置,j表示终止位置,所以我肯定是想求出dp[1][4]间的最大值但是我从1到4可是如图这三种截取方法,所以我先从小的开始记录。
dp[1][1]=4;dp[2][2]=4;dp[3][3]=5;dp[4][4]=9。然后我在长度为2的时候记录,dp[1][2]=4+4=8,dp[2][3]=8+5=14;dp[3][4]=14+9=23;这样加起来的值就是8+14+23=45;但是如果我反过来呢?dp[1][2]=5+9=14;dp[2][3]=14+4=18;dp[3][4]=18+4=22;这样加起来的值就是14+18+22=54。很明显,54就是所求的最大值。
如图,如果我相求圈着的这个三个的值,我完全可以有图上这两种分割,并且分割出来的值是已经知道的了。
动态规划的思想:先两两合并,在三三合并,最后再NN合并,在合并过程中,较大的区间可以拆分成已经的小区间进行计算,省时又省力。比如,我可以在三三合并的时候可以拆分成一一还有二三相加。即把当前阶段的合并方法细分成前一阶段已计算出的方法,选择其中的最优方案。
具体来说我们应该定义一个数组dp[i,j]用来表示合并方法,i表示从编号为i的石头开始合并,j表示所求区间的结尾,sum表示的是石头的数量。
对于上面的例子来说,
第一阶段:dp[1][1],dp[2][2],dp[3][3],dp[4][4] 因为一开始还没有合并,所以这些值应该全部为0。
第二阶段:两两合并过程如下,其中sum(i,j)表示石头的数量,即从i开始数j个数的和
dp[1,2]=dp[1,1]+dp[2,2]+sum[1,2];
dp[2,3]=dp[2,2]+dp[3,3]+sum[2,3];
dp[3,4]=dp[3,3]+dp[4,4]+sum[4,4];
第三阶段:三三合并可以拆成两两合并,拆分方法有两种,前两个为一组或后两个为一组
dp[1,3]=dp[1,2]+dp[3,3]+sum[1,3]或dp[1,3]=dp[1,1]+dp[2,3]+sum[1,3];取其最优
dp[2,4]=dp[2,2]+dp[3,4]+sun[2,4]或dp[2,4]=dp[2,3]+dp[3,3]+sum[2,4];取其最优
第四阶段:四四合并的拆分方法用三种,同理求出三种分法的得分,取其最优即可。以后第五阶段、第六阶段依次类推,最后在第六阶段中找出最优答案即可。
动态方程为dp[i][j]=dp[i][k]+dp[k+1][j]+sum[i][j];
参考代码。
#include <iostream>
#include <cstdio>
#include <cstring> using namespace std; //#define MAX 999999 int main ()
{
int dp[][],sum[][],a[];
int n;
while(~scanf("%d",&n))
{
//memset(dp,MAX,sizeof(dp));
for (int i=; i<=n; i++)
scanf("%d",&a[i]);
for (int i=; i<=n; i++)
{
dp[i][i]=;//初始化为0
sum[i][i]=a[i];//将每堆石子的个数赋值进来
}
for (int len=; len<n; len++)//按长度从小到大枚举
{
for (int i=; i<=n&&i+len<=n; i++)//i表示开始位置
{
int j=len+i; //j表示长度为len的一段区间的结束位置
for (int k=i; k<j; k++) //用k来表示分割区间
{
sum[i][j]=sum[i][k]+sum[k+][j];
if (dp[i][j]<dp[i][k]+dp[k+][j]+sum[i][j])
dp[i][j]=dp[i][k]+dp[k+][j]+sum[i][j];
//cout<<i<<" "<<j<<" "<<sum[i][j]<<" "<<k<<" "<<dp[i][j]<<endl;
}
}
}
cout<<dp[][n]<<endl;
}
return ;
}
http://acm.nyist.net/JudgeOnline/problem.php?pid=737
这是一道类似的题目,和上述代码有点区别,把7,15,31行修改一下即可哦~
区间DP(总结)的更多相关文章
- 【BZOJ-4380】Myjnie 区间DP
4380: [POI2015]Myjnie Time Limit: 40 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 162 Solved: ...
- 【POJ-1390】Blocks 区间DP
Blocks Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 5252 Accepted: 2165 Descriptio ...
- 区间DP LightOJ 1422 Halloween Costumes
http://lightoj.com/volume_showproblem.php?problem=1422 做的第一道区间DP的题目,试水. 参考解题报告: http://www.cnblogs.c ...
- BZOJ1055: [HAOI2008]玩具取名[区间DP]
1055: [HAOI2008]玩具取名 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1588 Solved: 925[Submit][Statu ...
- poj2955 Brackets (区间dp)
题目链接:http://poj.org/problem?id=2955 题意:给定字符串 求括号匹配最多时的子串长度. 区间dp,状态转移方程: dp[i][j]=max ( dp[i][j] , 2 ...
- HDU5900 QSC and Master(区间DP + 最小费用最大流)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5900 Description Every school has some legends, ...
- BZOJ 1260&UVa 4394 区间DP
题意: 给一段字符串成段染色,问染成目标串最少次数. SOL: 区间DP... DP[i][j]表示从i染到j最小代价 转移:dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k ...
- 区间dp总结篇
前言:这两天没有写什么题目,把前两周做的有些意思的背包题和最长递增.公共子序列写了个总结.反过去写总结,总能让自己有一番收获......就区间dp来说,一开始我完全不明白它是怎么应用的,甚至于看解题报 ...
- Uva 10891 经典博弈区间DP
经典博弈区间DP 题目链接:https://uva.onlinejudge.org/external/108/p10891.pdf 题意: 给定n个数字,A和B可以从这串数字的两端任意选数字,一次只能 ...
- 2016 年沈阳网络赛---QSC and Master(区间DP)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5900 Problem Description Every school has some legend ...
随机推荐
- spring boot 2.0 + 静态资源被拦截,怎么办?
问题描述:使用springboot 2.0后,按照springboot 1.5版本(以下简称旧版)的方式去配置项目.结果发现静态资源访问不到了,本文对此情况分析.处理 项目结构: 直接上图 如果是在旧 ...
- 15分钟入门lua
目录:[ - ] -- 1. Variables and flow control. -- 2. Functions. -- 3. Tables. -- 3.1 Metatables and meta ...
- linux机器之间拷贝和同步文件命令
1 不同机器拷贝文件 scp 文件 登录用户@机器IP:/目录/子目录 scp filename test@10.20.130.202:/home/test/ 2 文件[夹]同步 rsync ...
- LeetCode--070--爬楼梯
problem description: 假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 ...
- 用Omniauth来Login with Facebook(Go-rails课程)
https://gorails.com/episodes/login-with-facebook?autoplay=1 大概看了一遍,留了视频的截图. https://gorails.com/epis ...
- python中的注意事项
.python 中的 and 从左到右计算表达式,若所有值均为真,则返回最后一个值,若存在假,返回第一个假值: or 也是从左到有计算表达式,返回第一个为真的值: 其中数字 0 是假,其他都是真: 字 ...
- 关于二级指针的使用(使用node指针建树)
struct node { int v; node *l,*r; }*p; 使用二级指针建树的话,如果p是非全局变量且一开始没有指向变量的话递归建树时必然要传递参数,但是如果只是简单的build(no ...
- spring cloud学习(四) Fegin 的使用
Feign 的使用 什么是Feign? Feign : Declarative REST clients. Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创 ...
- USART相关问题
最近发现一个FT232+stm32的USB转串口问题,不能理解,记录下来. PC和STM32通讯,USB-B连接,连接方式如下所示: 上图为USB口引出USB_N/USB_P/USB_EN三个PIN脚 ...
- 跟我一起学习ASP.NET 4.5 MVC4.0(一)
跟我一起学习ASP.NET 4.5 MVC4.0(一) 由于上面一个项目使用的是ASP.NET4.0 MVC3.0,在招人的时候发现很多人有听说过MVC,但是却是没用过,对MVC也只是一知半解,最 ...