[NOI1995]石子合并 题解
一道经典的dp题
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.
我们先看下这道题的简单版本
有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
这道题不是环状的,我们可以直接dp解决,一开始我设的是f[i][j]表是合并i-j这个区间内的最小代价,于是有了状态转移方程
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]) (i<=k<=j)
于是写下了下面的代码
#include<bits/stdc++.h>
using namespace std;
int n,f[110][110],a[110];
int s[110];
int main(){
scanf("%d",&n);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
f[i][i]=0;
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=n;++i){
for(int j=i;j<=n;++j){
for(int k=i;k<=j;++k){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
}
}
}
printf("%d",f[1][n]);
return 0;
}
然鹅答案错误,为什么?
在同机房的大佬的帮助下我明白了
因为求大区间是要用到小区间的值,可是上面这个程序固定了起点就一直向后跑会导致有些点更新过晚,要用的时候却用不到,于是我写下了下面的代码
#include<bits/stdc++.h>
using namespace std;
int n,f[110][110],a[110],T=10;
int s[110];
int main(){
scanf("%d",&n);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
f[i][i]=0;
s[i]=s[i-1]+a[i];
}
while(T--){
for(int i=1;i<=n;++i){
for(int j=i;j<=n;++j){
for(int k=i;k<=j;++k){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
}
}
}
}
printf("%d",f[1][n]);
return 0;
}
既然一遍跑不出答案,那我多跑几遍不就好了,同机房的大佬都震惊了,虽然答案是对的,但却并不是正解,正解应该是在外面枚举长度,再枚举起点,算出终点dp
代码
#include<bits/stdc++.h>
using namespace std;
int n,f[110][110],a[110],T=10;
int s[110];
int main(){
scanf("%d",&n);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
f[i][i]=0;
s[i]=s[i-1]+a[i];
}
for(int L=2;L<=n;++L){
for(int i=1;i<=n;++i){
int j=i+L-1;
for(int k=i;k<=j;++k){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
}
}
}
printf("%d",f[1][n]);
return 0;
}
回到 noi1995这道题,我们看到环便可直接加倍断环成链(套路),其余思路同上面相似
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,f[410][410],g[410][410],a[410];
int s[410],maxn,minn=1<<30;
int main(){
scanf("%d",&n);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
f[i][i]=0;
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=n;++i){
s[i+n]=s[i+n-1]+a[i];
f[i+n][i+n]=0;//这个初始化一定要记得
}
for(int L=2;L<=n;++L){
for(int i=1;i<=n+n;++i){//起点可以枚举到2n
int j=i+L-1;
if(j>n*2) break;//不符合
for(int k=i;k<j;++k){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
g[i][j]=max(g[i][j],g[i][k]+g[k+1][j]+s[j]-s[i-1]);
}
}
}
for(int i=1;i<=n;++i){
maxn=max(maxn,g[i][i+n-1]);
minn=min(minn,f[i][i+n-1]);
}
printf("%d\n%d\n",minn,maxn);
return 0;
}
[NOI1995]石子合并 题解的更多相关文章
- 洛谷 P1880 [NOI1995]石子合并 题解
P1880 [NOI1995]石子合并 题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试 ...
- P1880 [NOI1995]石子合并[区间dp+四边形不等式优化]
P1880 [NOI1995]石子合并 丢个地址就跑(关于四边形不等式复杂度是n方的证明) 嗯所以这题利用决策的单调性来减少k断点的枚举次数.具体看lyd书.这部分很生疏,但是我还是选择先不管了. # ...
- 区间DP小结 及例题分析:P1880 [NOI1995]石子合并,P1063 能量项链
区间类动态规划 一.基本概念 区间类动态规划是线性动态规划的拓展,它在分阶段划分问题时,与阶段中元素出现的顺序和由前一阶段的那些元素合并而来由很大的关系.例如状态f [ i ][ j ],它表示以已合 ...
- P1880 [NOI1995]石子合并 区间dp
P1880 [NOI1995]石子合并 #include <bits/stdc++.h> using namespace std; ; const int inf = 0x3f3f3f3f ...
- 【区间dp】- P1880 [NOI1995] 石子合并
记录一下第一道ac的区间dp 题目:P1880 [NOI1995] 石子合并 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码: #include <iostream> ...
- 洛谷 P1880 [NOI1995] 石子合并(区间DP)
传送门 https://www.cnblogs.com/violet-acmer/p/9852294.html 题解: 这道题是石子合并问题稍微升级版 这道题和经典石子合并问题的不同在于,经典的石子合 ...
- [洛谷P1880][NOI1995]石子合并
区间DP模板题 区间DP模板Code: ;len<=n;len++) { ;i<=*n-;i++) //区间左端点 { ; //区间右端点 for(int k=i;k<j;k++) ...
- NOI1995石子合并&多种石子合并
题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1 ...
- 区间DP初探 P1880 [NOI1995]石子合并
https://www.luogu.org/problemnew/show/P1880 区间dp,顾名思义,是以区间为阶段的一种线性dp的拓展 状态常定义为$f[i][j]$,表示区间[i,j]的某种 ...
随机推荐
- 激活函数、正向传播、反向传播及softmax分类器,一篇就够了!
1. 深度学习有哪些应用 图像:图像识别.物体识别.图片美化.图片修复.目标检测. 自然语言处理:机器创作.个性化推荐.文本分类.翻译.自动纠错.情感分析. 数值预测.量化交易 2. 什么是神经网络 ...
- AppBoxFuture: 123挨个站-数据按序存储
最近几天在优化存储的编码规则,顺带把之前设计了但未实现的倒排序一并实现了.由于所有数据(元数据.实体.索引等)都映射至RocksDB的Key-Value存储,所以必须扩展RocksDB的自定义比较 ...
- Java ActionListenner类的一些理解
Java的ActionListenner事实上我去年年这个时候大概就已经接触到了,也学会了比较简单的使用.但却始终不能理解ActionListenner的一系列的运行是怎么维持这么一个联系的? 我产生 ...
- 02.Mybatis的动态代理方式实现增删改查
动态代理的方式实现增删改查: 通过约定的方式定位sql语句 约定 > 配置文件 > 硬编码 约定的目标是省略掉通过硬编码的方式定位sql的代码,通过接口直接定位出sql语句,以下代码为通过 ...
- Java虚拟机学习笔记(二)--- 判断对象是否存活
Java堆中存放着所有的对象实例,垃圾收集器在堆进行回收之前,需要判断对象是“存活”还是“死亡”(即不可能再被任何途径引用的对象). 最常见的一种判断对象是否存活算法是引用计数算法, 给对象加一个引用 ...
- 转载 | embed用法(网站中视频、音频的添加)
网站中添加视频: <embed src="http://player.video.qiyi.com/390cf6c74450e4c70b7bd2d883169914/0/0/w_19r ...
- win7-BIOS中开启AHCI模式电脑蓝屏怎么办?
win7-BIOS中开启AHCI模式电脑蓝屏怎么办? 来源:U大师 u盘装系统 不少网友都表示给电脑安装win7系统后,如果在BIOS中开启IDE模式就一切正常而为AHCI模式时就会出现蓝屏.其实那是 ...
- MQ 服务器错误代码2035
MQ 服务器错误代码20352013-06-12 19:29:39 搭建一个MQ7.1服务器,用了一个小的demo测试程序,结果报错, 测试代码: import com.ibm.mq.MQC; imp ...
- Java——类型信息
1.Class对象 Class对象是一个特殊的对象,它包含了与类有关的信息.Class对象就是用来创建类的所有常规对象的. 类是程序的一部分,每个类都有一个Class对象,每当编写并且编译一个新类,就 ...
- Win服务程序编写以及安装一般步骤
Win服务程序编写以及安装一般步骤 Windows服务的优点有:1. 能够自动运行.2. 不要求用户交互.3. 在后台运行.本文将介绍常见服务程序编写的一般步骤以及注意事项. 设计服务程序实例: 创建 ...