石子合并(3种变形)

<1>

题目:

N堆石子排成一排(n<=100),现要将石子有次序地合并成一堆,规定每次只能选相邻的两堆合并成一堆,并将新的一堆的石子数,记为改次合并的得分,编一程序,由文件读入堆数n及每堆石子数(<=200);

(1)选择一种合并石子的方案,使得做n-1次合并,得分的总和最少;

(2)选择一种合并石子的方案,使得做n-1次合并,得分的总和最多;

输入格式

第一行为石子堆数n

第二行为每堆石子数,每两个数之间用一空格分隔。

输出格式

从第1行为得分最小

2行是得分最大。

样例

样例输入

 4
 4 5 9 4

样例输出

 44
 54

特点:

仅是一排石子,而且只能是相邻两个石子相邻可以合并,所以第1个石子只能与右边的合并,第n个石子只能与左边的合并,所以用区间dp简单枚举合并即可。

数组表示:(以下同)

f[i][j]:从ij的区间的最大/最小值;

sum[i]i的前缀和(便于计算);

动态规划:

阶段:

区间长度dd=1时初始值即石子本身分数,所以从d=2开始枚举,以此到d=n

状态:

ij的区间的最大/最小值;

决策:

是否将从ik的区间与从k+1j的区间合并,若合并即加上sum[i]-sum[j-1]ij的分数);

动态转移方程:

f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[i]-sum[j-1]);

f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+sum[i]-sum[j-1]);

注意:

最小值f[i][j]的初始值为0x7f7f7f7f

最大值f[i][j]的初始值为0

代码:

 #include <bits/stdc++.h>
using namespace std;
const int maxn=+;
const int INF=0x3f3f3f3f;
int n;
int f1[maxn][maxn],f2[maxn][maxn];
int sum[maxn];
int a[maxn];
int minx=INF,maxx=;
void MIN(){
for(int d=;d<=n;d++){
for(int i=,j;(j=i+d-)<=n;i++){
for(int k=i;k<j;k++){
f1[i][j]=min(f1[i][j],f1[i][k]+f1[k+][j]+sum[j]-sum[i-]);
}
}
}
}
void MAX(){
for(int d=;d<=n;d++){
for(int i=,j;(j=i+d-)<=n;i++){
for(int k=i;k<j;k++){
f2[i][j]=max(f2[i][j],f2[i][k]+f2[k+][j]+sum[j]-sum[i-]);
}
}
}
}
int main(){
memset(f1,INF,sizeof(f1));
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=;i<=n;i++){
if(i==){
sum[i]=a[i];
}else{
for(int j=;j<=i;j++){
sum[i]+=a[j];
}
}
}
for(int i=;i<=n;i++){
f1[i][i]=;
}
MIN();
MAX();
printf("%d\n",f1[][n]);
printf("%d\n",f2[][n]);
return ;
}

<2>

题目:

在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分。

输入格式

数据的第1行试正整数N,(1≤ N ≤100),表示有N堆石子。

2行有N个数,分别表示每堆石子的个数。

输出格式

输出共2行,第1行为最小得分,第2行为最大得分。

样例

样例输入

 4
 4 4 5 9

样例输出

 43
 54

特点:

与上一题不同的是,这里是圆形操场,即现在的石子是一个环,现在第1个石子与第n个石子算是相邻,也是很简单,自己将数组存储两边石子的分数,便可以模拟环,然后直接按上次的dp处理即可。

注意:

此时的d还是枚举到n

ij则需要枚举到2*n

代码:

 #include <bits/stdc++.h>
using namespace std;
const int maxn=+;
const int INF=0x3f3f3f3f;
int n;
int f1[maxn][maxn],f2[maxn][maxn];
int sum[maxn];
int a[maxn];
int minx=INF,maxx=;
void MIN(){
for(int d=;d<=n;d++){
for(int i=,j;(j=i+d-)<=*n;i++){
f1[i][j]=INF;
for(int k=i;k<j;k++){
f1[i][j]=min(f1[i][j],f1[i][k]+f1[k+][j]+sum[j]-sum[i-]);
}
}
}
}
void MAX(){
for(int d=;d<=n;d++){
for(int i=,j;(j=i+d-)<=*n;i++){
f2[i][j]=;
for(int k=i;k<j;k++){
f2[i][j]=max(f2[i][j],f2[i][k]+f2[k+][j]+sum[j]-sum[i-]);
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
a[n+i]=a[i];
}
for(int i=;i<=*n;i++){
sum[i]=sum[i-]+a[i];
}
MIN();
MAX();
int zuix=INF,zuid=;
for(int i=;i<=n;i++){
zuix=min(zuix,f1[i][i+n-]);
zuid=max(zuid,f2[i][i+n-]);
}
printf("%d\n%d\n",zuix,zuid);
return ;
}

<3>

题目:

在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆最大得分。

输入格式

数据的第1行试正整数N,1≤N≤2000,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数。

输出格式

输出共1行,最大得分。

样例

样例输入

 4
 4 4 5 9

样例输出

 54

注意:

虽然一看这题与<2>完全一样,但是仔细看的话,N的范围发生了变化,那么就不能与<1>、<2>一样用直接dp的方法,上两次只有N3的​效率,所以这次得需要优化。

区间dp的优化方式有四边不等式法,但是这里是求最大值,没有单调性,无法用四边不等式。

但是最大值有一个性质,总是在两个端点的最大者中取到。

动态转移方程式:

f[i][j]=max(f[i][j-1],f[i+1][j])+sum[j]-sum[i-1]

代码:

 
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+,INF=0x3f3f3f3f;
int n,m,f[][],ans,a[maxn],sum[];
int main(){
cin>>n;
for(int i=;i<=n;i++){
cin>>a[i];
a[i+n]=a[i];
sum[i]=a[i]+sum[i-];
}
for(int i=n+;i<=*n;i++){
sum[i]=sum[i-]+a[i];
}
for(int d=;d<=n;d++){
for(int i=,j;(j=i+d-)<=n*;i++){
f[i][j]=max(f[i][j-],f[i+][j])+sum[j]-sum[i-];
}
}
int ansmax=;
for(int i=;i<=n;i++){
ansmax=max(ansmax,f[i][i+n-]);
}
cout<<ansmax<<endl;
return ;
}

石子合并——区间dp的更多相关文章

  1. 洛谷 P1880 [NOI1995] 石子合并(区间DP)

    传送门 https://www.cnblogs.com/violet-acmer/p/9852294.html 题解: 这道题是石子合并问题稍微升级版 这道题和经典石子合并问题的不同在于,经典的石子合 ...

  2. 石子合并 区间dp模板

    题意:中文题 Description 在操场上沿一直线排列着 n堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的两堆石子合并成新的一堆, 并将新的一堆石子数记为该次合并的得分.允许在第一次合 ...

  3. HDU4632 Poj2955 括号匹配 整数划分 P1880 [NOI1995]石子合并 区间DP总结

    题意:给定一个字符串 输出回文子序列的个数    一个字符也算一个回文 很明显的区间dp  就是要往区间小的压缩! #include<bits/stdc++.h> using namesp ...

  4. 石子合并 区间DP模板题

    题目链接:https://vjudge.net/problem/51Nod-1021 题意 N堆石子摆成一条线.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石 ...

  5. 洛谷 P1080 石子合并 ( 区间DP )

    题意 : 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分.试设计出1个算法,计算出将N堆石子合并成1堆 ...

  6. 洛谷P1880 石子合并(环形石子合并 区间DP)

    题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1 ...

  7. HRBUST - 1818 石子合并 区间dp入门

    有点理解了进阶指南上说的”阶段,状态和决策“ /* 区间dp的基础题: 以区间长度[2,n]为阶段,枚举该长度的区间,状态dp[l][r]表示合并区间[l,r]的最小费用 状态转移方程dp[l][r] ...

  8. HDU 3506 (环形石子合并)区间dp+四边形优化

    Monkey Party Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Tot ...

  9. P1880 [NOI1995]石子合并 区间dp+拆环成链

    思路 :一道经典的区间dp  唯一不同的时候 终点和起点相连  所以要拆环成链  只需要把1-n的数组在n+1-2*n复制一遍就行了 #include<bits/stdc++.h> usi ...

随机推荐

  1. Maven发布Release到中心仓库历程记录(无个人域名)

    Maven发布Release到中心仓库历程记录(无个人域名) 前言 因为前段时间自己做了一个爬虫项目(地址),自己很希望分享到maven中心仓库上,感觉拥有自己的jar包令我兴奋,便开始了maven发 ...

  2. 【Spring注解驱动开发】使用@Scope注解设置组件的作用域

    写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...

  3. 详解CurrentHashMap之预习篇

    CurrentHashMap的出现时为了解决HashMap的高并发导致OOM的缺陷,并且能够保证高性能读取.那么解读CurrentHashMap需要具备哪些知识的呢? HashMap 解读 Java ...

  4. idea针对有外联jar包的项目如何编译成可运行的jar包

    1.打开file-->project structure 2.如下图所示,创建 3.在空白处右键点击“create directory”创建一个“”“libs”文件夹 4.把项目所需的jar吧, ...

  5. Spring:工厂模式哪里解耦了?

    菜瓜:我一定是太菜了,为什么别人说Spring屏蔽了new关键字创建对象就很丝滑?我完全get不到这个操作的好处啊,我自己写new它也很香啊 水稻:emmmm,换个角度想啊,如果把现在用的注解@Aut ...

  6. MyISAM 和 InnoDB 索引结构及其实现原理

    数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询.更新数据库表中数据. 索引的实现通常使用B_TREE. B_TREE索引加速了数据访问,因为存储引擎不会再去扫描整张表得到需要的数据; ...

  7. [每日一题2020.06.07]codeforces Round #627 (Div. 3)

    problem A /* * Author: RoccoShi * Time: 2020-06-07 19:37:51 */ #include <bits/stdc++.h> using ...

  8. 深入理解 nth-child 和 nth-of-type 的区别

    ele:nth-of-type(n)  为什么叫 of-type ,就是说它是以“type”来区分的,也就是说ele:nth-of-type(n)指的是父元素下第n个ele元素. ele:nth-ch ...

  9. cb19a_c++_只适合string类型的操作_提取_追加_替换

    *cb19a_c++_只适合string类型的操作_提取_追加_替换三个substr重载函数-获取一个字符串的一部分六个append重载函数-追加字符十个replace重载函数-替换更换 重载函数越多 ...

  10. WebBrowser禁用触摸缩放

    最近做一个WPF触屏的项目,引用到WebBrowser控件,由于是触屏的所以控件里的网页可以缩放,客户提出要求,屏蔽这缩放功能. 于是网上找了很多资料,也换过控件,WebView2 控件使用Micro ...