合并石子(区间DP)
有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小。
区间DP思想:现在小区间进行DP得到最优解,然后再利用小区间的最优解组合并求大区间的最优解。(需要从小到大枚举所有可能的区间)
代码(没提交过,不过应该正确):
include
using namespace std;
const int maxn1=300;
int main()
{
int n,a[maxn1]={0},sum[maxn1]={0};
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i],sum[i]=a[i]+sum[i-1]; //前缀和
int dp[maxn1][maxn1]={0}; //dp[i][j]表示区间[i,n]的最小花费
for(int len=1;len<n;len++) //枚举所有可能的区间
{
for(int i=1;i<=n-len;i++)
{
dp[i][i+len]=INT_MAX;
for(int k=i;k<i+len;k++)
dp[i][i+len]=min(dp[i][i+len],dp[i][k]+dp[k+1][i+len]+sum[i+len]-sum[i-1]);
}
}
cout<<dp[1][n]<<endl;
return 0;
}
这样写很容易理解,但复杂度为O(n^3),基本最多只能计算250堆石子。
在网上看了一个平行四边形对区间DP的优化,复杂度基本可以维持在O(n^2),但是我却始终不理解其原理,不过大概按葫芦画瓢,写了一个(并注释了与之前O(n^3)的不同):
include
using namespace std;
const int maxn1=3000;
int main()
{
int n,a[maxn1]={0},sum[maxn1]={0},s[maxn1][maxn1];
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i],sum[i]=a[i]+sum[i-1];
for(int i=1;i<=n;i++) //多加
s[i][i]=i; //多加 (记录区间最优解的位置)
int dp[maxn1][maxn1]={0};
for(int len=1;len<n;len++)
{
for(int i=1;i<=n-len;i++)
{
dp[i][i+len]=INT_MAX;
for(int k=s[i-1][i+len];k<=s[i+1][i+len];k++) //改变
if(dp[i][k]+dp[k+1][i+len]+sum[i+len]-sum[i-1]<dp[i][i+len]) //改变
{
dp[i][i+len]=dp[i][k]+dp[k+1][i+len]+sum[i+len]-sum[i-1]; //改变
s[i][i+len]=k; //改变
}
}
}
cout<<dp[1][n]<<endl;
return 0;
}
合并石子(区间DP)的更多相关文章
- 洛谷P1880 石子合并(区间DP)(环形DP)
To 洛谷.1880 石子合并 题目描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1 ...
- 直线石子合并(区间DP)
石子合并 时间限制:1000 ms | 内存限制:65535 KB 描述有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费 ...
- CH5301 石子合并【区间dp】
5301 石子合并 0x50「动态规划」例题 描述 设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300).每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆, ...
- zjnu 1181 石子合并(区间DP)
Description 在操场上沿一直线排列着 n堆石子. 现要将石子有次序地合并成一堆.规定每次仅仅能选相邻的两堆石子合并成新的一堆, 并将新的一堆石子数记为该次合并的得分.同意在第一次合并前对调一 ...
- nyoj 737 石子合并(区间DP)
737-石子合并(一) 内存限制:64MB 时间限制:1000ms 特判: No通过数:28 提交数:35 难度:3 题目描述: 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为 ...
- 石子合并2——区间DP【洛谷P1880题解】
[区间dp让人头痛……还是要多写些题目练手,抽空写篇博客总结一下] 这题区间dp入门题,理解区间dp或者练手都很妙 ——题目链接—— (或者直接看下面) 题面 在一个圆形操场的四周摆放N堆石子,现要将 ...
- 石子合并问题 /// 区间DP oj2025
Description 在一个圆形操场的四周摆放着n堆石子.现要将石子有次序地合并成一堆. 规定每次只能选相邻的两堆石子合并成新的一堆,并将新得的这堆石子数记为该次合并的得分. 试设计一个算法,计算出 ...
- 石子合并 (区间DP)
一.试题在一个园形操场的四周摆放N堆石子(N≤100),现要将石子有次序地合并成一堆.规定每次仅仅能选相邻的两堆合并成新的一堆,并将新的一堆的石子数.记为该次合并的得分.编一程序.由文件读入堆数N及每 ...
- 合并傻子//区间dp
P1062 合并傻子 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 从前有一堆傻子,钟某人要合并他们~但是,合并傻子是要掉RP的...... 描述 在一个园 ...
- nyoj 737 石子合并 经典区间 dp
石子合并(一) 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆 ...
随机推荐
- python 模块调用的几种方式
在python里面又很多模块,或者引用第三方模块,python 模块调用的几种方式,下面详细解说 1,import 模块名 2,from 模块 import 模块里面的小功能 3,from 模块 ...
- C++对象构造时,构造函数运行时并不知道VT的存在
class A {public: A() { init(); } virtual void init() { printf("A::init\n"); }}; class B : ...
- P3191 [HNOI2007]紧急疏散EVACUATE
传送门 这一题很容易想到网络流 一开始傻逼地模拟整个图每一个时间的情况,显然会爆炸 发现我们只要考虑起点到门之间的距离,不用每一步只走一格 所以直接 $BFS$ 预处理距离然后二分答案,网络流判断即可 ...
- javascript(DOM)实例
JavaScript学习笔记 JS补充笔记 实例之跑马灯,函数创建.通过ID获取标签及内部的值,字符串的获取与拼接.定时器的使用 使用定时器实现在console中打印内容 Dom选择器使用与调试记录 ...
- k3 cloud支付申请单下推付款单时候提示未将对象引用设置到对象的实例
项目支付申请部门没有币别没有填写,没有把币别带过来才
- go中基本数据类型转换为string类型的方法
代码 // 基本数据类型转换为string类型 package main import ( "fmt" "strconv" ) func main() { // ...
- 移动端300ms延迟原理,穿透、遮罩层滑动导致下面滑动总结
遮罩层滑动导致下面滑动 1,阻止弹层滑动,使用默认事件,使用这种方式弹层不能滑动 document.getElementById("model").addEventListener ...
- VirtualBox中安装CentOS 7
1.如下所示图,点击“新建”,创建一个新的虚拟机 2.类型选择Linux,版本选择Red Hat,下一步 3.分配内存大小,电脑8G内存,所以分给虚拟机2G,选择下一步 4.选择“现在创建虚拟硬盘” ...
- 2018-9-1-win10-17025-触摸bug
title author date CreateTime categories win10 17025 触摸bug lindexi 2018-09-01 09:50:18 +0800 2018-2-1 ...
- Java架构师需要掌握的技术栈