1. 题干

描述

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

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

输入

第1行一个正整数N,1≤N≤2000,表示有N堆石子.

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

输出

共1行,最大得分

输入样例1

4
4 4 5 9

输出样例1

54

2. 解

1) 原理概述

以最大值为例。

本问题采用了分冶的思想,是先求解小区间中的解,再合并到大区间中。

Fmax[i][j]意为区间[i,j]内合并的最大得分,t[i][j]意为区间[i,j]中的石子总分。

① 状态转移方程:

② 经过平行四边形优化后的状态转移方程:

平行四边形优化的结论:使两堆的合并值最大的分割点,一定将堆[i,j]分成[i+1,j],[i,i]或者[i,j-1],[j,j]这两堆。
证明:(下图来自 HUST 课堂,笔者根据自己的理解将证明完善并添加了颜色和符号标记)

③ 环状结构优化(下图来自 HUST 课堂):

2) 代码实现(以循环结构为例):

#include<stdio.h>
#pragma warning(disable:4996)
#define TYPE_ull unsigned long long
//DP问题
TYPE_ull t[4005] = { 0 };
TYPE_ull F[4005][4005] = { 0 }, Max = 0;
TYPE_ull max(TYPE_ull i, TYPE_ull j)
{
if (i > j)
return i;
else return j;
}
TYPE_ull f(int n)
{
Max = 0;
//F[i][j]意为区间(i,j)内合并的最大得分
//for (int i = 1; i <= n; ++i)
//{ // F[i][i + 1] = t[i + 1] - t[i - 1];//取相邻两数合并得分为两数之和
//}
//for (int i = 1; i <= n; ++i)
//{
// F[i][i + 2] = max(F[i][i + 1], F[i + 1][i + 2]) + t[i + 2] - t[i - 1];//取间隔为2的F区间
//}
//...
for (int v = 1; v < n; ++v)//间隔为v,从间隔为1算起,将递归转换为循环,算间隔为n-1为止即可
{
for (int i = 1; i <= 2 * n; ++i)
{
if (i + v < 2 * n)//注意不能越界
F[i][i + v] = max(F[i][i + v - 1], F[i + 1][i + v]) + t[i + v] - t[i - 1];//取间隔为v的F区间
}
}
for (int i = 1; i <= n; ++i)
{
Max = max(F[i][n + i - 1], Max);
}
return Max;
} int main()
{
int n, k;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &k);
t[i] = t[i - 1] + k;
}
for (int i = 1; i <= n; ++i)
{
t[n + i] = t[n] + t[i];
}
printf("%llu\n", f(n));
return 0;
}

3) 笔者被坑到的地方

  1. 迭代转循环:分冶思想,若直接计算F[1][n]这个最大问题,那么小问题还没算出来,最终的结果肯定是错的。为了计算小问题,可以将所有的小问题从最小的开始求。设定间隔为1,先写一个求解所有间隔为1的循环:
for (int i = 1; i <= n; ++i)
{
F[i][i + 1] = t[i + 1] - t[i - 1];//取相邻两数合并得分为两数之和
}

然后再写间隔为2的:

for (int i = 1; i <= n; ++i)
{
F[i][i + 2] = max(F[i][i + 1], F[i + 1][i + 2]) + t[i + 2] - t[i - 1];//取间隔为2的F区间
}

最后把间隔处理成一个新的循环即可。

  1. 边界处理:要算间隔为1到(n-1)的所有区间,但是注意,当区间的初值为i的时候,它的末值最大仍然只能取n,区间长度最多为(n-i)。

【记录】OJ|区间DP|石子合并(环形)的更多相关文章

  1. 区间DP石子合并问题 & 四边形不等式优化

    入门区间DP,第一个问题就是线性的规模小的石子合并问题 dp数组的含义是第i堆到第j堆进行合并的最优值 就是说dp[i][j]可以由dp[i][k]和dp[k+1][j]转移过来 状态转移方程 dp[ ...

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

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

  3. P1880 [NOI1995]石子合并[环形DP]

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

  4. Luogu【P1880】石子合并(环形DP)

    先放上luogu的石子合并题目链接 这是一道环形DP题,思想和能量项链很像,在预处理过程中的手法跟乘积最大相像. 用一个m[][]数组来存储石子数量,m[i][j]表示从第 i 堆石子到第 j 堆石子 ...

  5. DP石子合并问题

    转自:http://www.hnyzsz.net/Article/ShowArticle.asp?ArticleID=735 [石子合并]    在一个圆形操场的四周摆放着n 堆石子.现要将石子有次序 ...

  6. 四边形不等式优化DP——石子合并问题 学习笔记

    好方啊马上就要区域赛了连DP都不会QAQ 毛子青<动态规划算法的优化技巧>论文里面提到了一类问题:石子合并. n堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的 ...

  7. 区间DP中的环形DP

    vijos1312 链接:www.vijos.org/p/1312 题目分析:经典的环形DP(区间DP) 环形DP,首先解环过程,把数组复制一遍,n个数变成2n个数,从而实现解环 dp[i][j]表示 ...

  8. 洛谷P1063 能量项链(区间DP)(环形DP)

    To 洛谷.1063 能量项链 题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的 ...

  9. 石子合并(直线版+环形版)&(朴素写法+四边形优化+GarsiaWachs算法)

    石子合并-直线版 (点击此处查看题目) 朴素写法 最简单常见的写法就是通过枚举分割点,求出每个区间合并的最小花费,从而得到整个区间的最小花费,时间复杂度为O(n^3),核心代码如下: ; i < ...

  10. 「区间DP」「洛谷PP3146 」[USACO16OPEN]248 G

    [USACO16OPEN]248 G 题目: 题目描述 Bessie likes downloading games to play on her cell phone, even though sh ...

随机推荐

  1. Luogu P10869 LCMs 题解 [ 黄 ] [ lcm ] [ 最短路 ]

    LCMs:很好的数论和构造题. 显然我们不可以直接建图跑最短路. 于是考虑分讨. 倍数关系 答案显然为 \(\max(a,b)\). 相等关系 答案显然为 \(0\). \(\gcd(a,b)> ...

  2. mybatis之生命周期及作用域

    SqlSessionFactoryBuilder 一旦创建了SqlSessionFactory之后就没有作用了 局部变量 SqlSessionFactory 可以理解为数据库的连接池 SqlSessi ...

  3. 2024年! kali高级配置加一键教程加前人的经验加后人的实践

    2024年! kali高级配置加一键教程加前人的经验加后人的实践 记录一下配置kali的过程,方便下次需要直接复制粘贴 直接终端按照顺序输入就可以配置好 作者已踩点,请放心 kali更换国内源 sud ...

  4. Dev Express WPF GridControl 数据导出到Excel

    Dev Express WPF 给控件提供了公共的导出方法: Export to PDF Export to HTML Export to MHT Export to Text Export to C ...

  5. Powershell 调用cmd 运行exe、bat、jar文件

    1. 配置路径 $nginxPath = "C:\path\to\nginx" $redisPath = "C:\path\to\redis" $ruoyiAd ...

  6. Qt Json序列化与反序列化

    Qt Json序列化与反序列化 Qt的一个用于序列化与反序列化的库 xpack,也可用于c++. 使用方法 下载库文件 xpack 标签 - Gitee.com 按照它的默认样子放好,建议单独放一个文 ...

  7. 火爆的 幻兽帕鲁/Palworld 单机➕联机 电脑游戏 免费畅游

    在广阔的世界中收集神奇的生物"帕鲁",派他们进行战斗.建造.做农活,工业生产等,这是一款支持多人游戏模式的全新开放世界生存制作游戏. ▼补丁主要内容 ・修复加载世界数据时,加载画面 ...

  8. Linux - Linux终端里的二维码

    qrencode:Linux 操作系统中生成二维码,点此进入下载页面 1.将tar包上传到 Linux 服务器上并解压:tar -zxvf qrencode-x.x.x.tar.gz 2.在 .bas ...

  9. excel 数字转中文大写金额

    1.在单元格中输入公式: =SUBSTITUTE(SUBSTITUTE(IF(-RMB(A1,2),TEXT(A1,";负")&TEXT(INT(ABS(A1)+0.5%) ...

  10. 探秘Transformer之(8)--- 位置编码

    探秘Transformer之(8)--- 位置编码 0x00 概述 位置编码(Positional Embedding)是一种用于处理序列数据的技术,被用来表示输入序列中的单词位置.在Transfor ...