Luogu 1880 合并石子
Luogu 1880 合并石子 (线性动态规划)
经典的区间型动态规划。
——————————————————————————————————
题干:https://www.luogu.org/problem/P1880
题目描述:
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.
输入格式:
数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.
输出格式:
输出共2行,第1行为最小得分,第2行为最大得分.
样例:
输入:
4
4 5 9 4
输出:
43
54
——————————————————————————————————
思路:
1.预处理前缀和:
先进行预处理,因为之后要用到i—j的石子和,所以先统计前缀和,a[j]-a[i-1]即为i—j的石子和,因为环状结构,所以处理到2*n;
2.最优子结构:
既然要得到最优解(以最大值为例),必须每个区间合并都是最优解,假设有
一个区间不是最大得分,那这个区间更改为最大得分,最终结果一定比原结果
更优,满足最优子结构。
3.状态:
既然是线性,那我们不妨定义dp[i][j]为从i合并到j的最大得分(最小得分)。
4.状态转移方程:
那我们如何得出状态转移方程: 可以枚举一个断点k,把一段长区间化为短区间,状态转移方程很明显:
dp[i][j]=max(dp[i][k]+dp[k+1][j]+a[j]-a[i-1]).
5.转移顺序:
这道题的状态转移方程很好想,但转移顺序确实一个难点,假设正着循环,枚举k来换分i,j,那么如果通过枚举i和j进行状态转移,很显然某些k值时并不能保证已经确定过所需状态,例如:
i : 1 to 10 ; j: 1 to 10 ; k : 1 to 9 ;
当i=1,j=5,k=3时,显然状态f[k+1][j]没有结果.
所以我们需要枚举区间长度,左右端点,保证先把长度为2的合并,
再合并3 to n,这样就可保证已经确定过所需状态。
6.环形结构如何处理:因为是环形结构 ,所以我们 在后面复制一遍前面的数,把石子数扩展到2 * n;
例: 我们以样例为例子:
4 5 9 4 —> 4 5 9 4 4 5 9 4
此时便包含了所有情况
(4 5 9 4)4 5 9 4
4(5 9 4 4)5 9 4
4 5 (9 4 4 5)9 4
4 5 9 (4 4 5 9)4
正确性显然;
7.结果: 最后只需统计长度为n区间内的最优解即可。
——————————————————————————————————
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 300 + 10;
int n,ansmin,ansmax,dp1[MAXN][MAXN],dp2[MAXN][MAXN];//用dp1数组记录i--j的最大得分,用dp2数组记录i--j的最小得分
int a[MAXN]; //用a数组记录前缀和,用a[j]-a[i-1]得到i--j的和。
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i+n]=a[i];a[i]+=a[i-1]; }for(int i=n+1;i<=2*n;i++)a[i]+=a[i-1]; //环状结构 ,所以开到2*n for(int p=1;p<n;p++) //区间长度{ for(int i=1,j=i+p;(j<n+n) && (i<n+n);i++,j=i+p) //左右端点{ dp2[i][j]=999999999; for(int k=i;k<j;k++) //断点{ dp1[i][j] = max(dp1[i][j], dp1[i][k]+dp1[k+1][j]+a[j]-a[i-1]); dp2[i][j] = min(dp2[i][j], dp2[i][k]+dp2[k+1][j]+a[j]-a[i-1]); //状态转移方程 dp[i][j]=max(dp[i][k]+dp[k+1][j]+a[j]-a[i-1]); } } } ansmin=1e9+7;ansmax=0;for(int i=1;i<=n;i++){ansmax=max(ansmax,dp1[i][i+n-1]);ansmin=min(ansmin,dp2[i][i+n-1]);}//最后统计长度为n区间的最大得分的最大值 ,最小得分的最小值 cout<<ansmin<<"\n"<<ansmax;return 0;
}
2019.10.26
By October
Luogu 1880 合并石子相关推荐
- 洛谷 P1775 合并石子(弱化版)
文章目录 合并石子(弱化版) 一.题目描述 二.思路 三.代码 合并石子(弱化版) 一.题目描述 https://www.luogu.com.cn/problem/P1775 设有 N(N \le 3 ...
- 蒟蒻吃药计划-治疗系列 #round 2 合并石子+乘积最大
1.合并石子 <信息学奥赛一本通>第五版 P371 第三节 T1 我就直接开始讲吧: Warning:这个题目和 合并果子 不一样!不一样!不一样!不一样!不一样!不一样!不一样!不一样! ...
- 合并石子 四边形不等式优化
题目描述 有一排石子,共n 堆.现要将石子有次序地合并成一堆.规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分.试设计一个算法,计算出将n堆石子合并成一堆的最小得分. ...
- 蓝桥杯-合并石子(java)
算法提高 合并石子 时间限制:2.0s 内存限制:256.0MB问题描述在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数.求 ...
- 合并石子 区间dp水题
合并石子 链接: nyoj 737 描述: 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N- ...
- 合并石子(三种方法)
合并石子 题目 在一个操场上一排地摆放着N堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分.请设计一个程序,计算出将N堆石子合并成 ...
- 有n堆石子,每次取出两堆合成一堆,每堆石子的个数即为合并石子所需要耗费的体力,求出合并所有石子堆所需要耗费的最小体力
有n堆石子,每次取出两堆合成一堆,每堆石子的个数即为合并石子所需要耗费的体力,求出合并所有石子堆所需要耗费的最小体力 典型的贪心题,即每次取出数量最少的两堆石子合并. 举个例子来说,假如有5堆石子,石 ...
- 2021.06.03合并石子+能量项链
2021.06.03合并石子+能量项链 题目描述 在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. ...
- 【luogu】 P1880 石子合并
原题原题原题原题原题 先贴上错误代码... ↓错误代码↓ #include <iostream> #include <cstdio> #include <cstring& ...
最新文章
- Java/Android基础-02
- python可视化脉搏和血氧数据并通过阈值动态调整、动态可视化异常值
- spring启动过程之源码跟踪(续beanfactory)--spring Debug
- MSCRM二次开发实现自动编号功能
- java二维数组数字数显次数_【每日一题】118.数组中数字出现的次数
- 微服务升级_SpringCloud Alibaba工作笔记0028---Nacos之Nacos集群配置下
- 5G加速向纵深发展 中国电信联合产业链开展“5G创新终端商用合作行动”
- laravel5.1 基于redis实现任务队列
- maven单元测试报java.lang.IllegalStateException: Failed to load ApplicationContext
- VC++中OpenGL的配置
- 资源分享 | 敬伟 PS 教程 ABCD 四套全集
- 非常好的Struts2教程
- l2范数求导_向量的L2范数求导
- 熊国正版游戏之TXT文字乱码【已解决】【rutracker】【byrut】【单机】【破解】【俄罗斯】
- 【智能优化算法-灰狼算法】基于非支配排序灰狼优化器(NS-GWO)算法求解多目标优化算法附matlab代码
- 蓝桥杯【学做菜】Java
- 在java中如何让背景图片连续不断地滚动_JS实现图片的不间断连续滚动
- win7系统(32位)安装CAD2004的方法
- The Webpage might be temporarily down or it may have moved permanently to a new web address解决
- mysql 创建用户 create user_MySQL数据库创建用户(CREATE USER)