合并石子(区间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堆石子并成为一堆.合并的过程只能每次将相邻的两堆 ...
随机推荐
- [AHOI2013]作业 (莫队+分块)
[AHOI2013]作业 (莫队+分块) 题面 给定了一个长度为n的数列和若干个询问,每个询问是关于数列的区间[l,r],首先你要统计该区间内大于等于a,小于等于b的数的个数,其次是所有大于等于a,小 ...
- apache2.4 只允许合法域名访问网站 禁止使用ip、非法域名访问
1.ip访问禁用ip访问 只能对应端口有效<VirtualHost *:80> ServerName xx.xx.xx.xx ServerAlias * <Location /> ...
- python学习笔记(11):文件的访问与函数式编程
一.文本文件读写的三种方法 1.直接读入 file1 = open('E:/hello/hello.txt') file2 = open('output.txt','w') #w是可写的文件 whil ...
- python学习笔记(9):容器
一.容器 0.判断所有的容器是否为空,用if not xxx(容器名):来进行判断 1.list 列表 序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一 ...
- c# 读取二进制文件并转换为 16 进制显示
string result = ""; string filePath = "xxx.bin"; if (File.Exists(filePath)) { by ...
- Archlinux笔记本安装手记
最近看着Linux Mint里一揽子乱七八糟的应用和散布各处的配置文件愈发烦躁,便想体验下大名鼎鼎的Arch,网上的帖子们把Arch Linux的安装难度描述的非常可怕,但实际上跟着Wiki一步一步来 ...
- Redis 复制功能详解
Redis 复制功能的几个重要方面: 1. 一个Master可以有多个Slave:2. Redis使用异步复制.从2.8版本开始,Slave会周期性(每秒一次)发起一个Ack确认复制流(replica ...
- AOP技术介绍--(引言)
软件设计因为引入面向对象思想而逐渐变得丰富起来.“一切皆为对象”的精义,使得程序世界所要处理的逻辑简化,开发者可以用一组对象以及这些对象之间的关系将软件系统形象地表示出来.而从对象的定义,进而到模块, ...
- bzoj4940 [Ynoi2016]这是我自己的发明 莫队+dfs序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4940 题解 对于换根操作,处理方法就很套路了. 首先先假定以 \(1\) 为根做一遍 dfs, ...
- k8s 1.9.0-手动安装-2
1 下载etcd新版 https://github.com/coreos/etcd/releases 直接下载k8s的二进制包 https://github.com/kubernetes/kubern ...