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. Kettle - 简介

    ETL简介 Kettle简介 transformation 和 job的区别 Kettle 的核心组件 Kettle 特点 Kettle 的目录说明 Kettle 的文件说明 ETL简介 ETL,Ex ...

  2. 大数据之路Week08_day06 (Zookeeper初识)

    让我们来回顾一下我们在学习Hadoop中的HDFS的时候,肯定见过下面这样的两幅图: 这副图代表着什么呢?它介绍的是Hadoop集群的高可靠,也就是前面提过的HA,仔细观察一下这副图,我们发现有两个N ...

  3. 『Python底层原理』--Python字符串的秘密

    在现代编程中,字符串是不可或缺的数据类型. 无论是处理用户输入.文件读写还是网络通信,字符串都扮演着核心角色. 然而,字符串的处理并非简单地将字符拼接在一起,它涉及到字符集.编码以及编程语言的底层实现 ...

  4. 读论文-新闻推荐系统:近期进展、挑战与机遇的评述(News recommender system_ a review of recent progress, challenges, and opportunities)

    前言 今天读的论文为一篇于2022年发表在"人工智能评论"(Artificial Intelligence Review)的论文,文章主要强调了NRS面临的主要挑战,并从现有技术中 ...

  5. 【数值方法-Python实现】Crout分解+追赶法实现

    涉及Crout分解.追赶法的线性方程组求解方法的Python实现. Codes def CroutLU(A:np.ndarray)->Tuple[np.ndarray,np.ndarray]: ...

  6. 基于近红外与可见光双目摄像头的活体人脸检测,文末附Demo

    基于近红外与可见光双目摄像头的活体人脸检测原理 人脸活体检测(Face Anti-Spoofing)是人脸识别系统中的重要一环,它负责验证捕捉到的人脸是否为真实活体,以抵御各种伪造攻击,如彩色纸张打印 ...

  7. 【CIM信息整合】关于三维建筑模型

    还是无暇细细检索并总结列出有逻辑的明确表述,以下很多地方都是人云亦云的复制,自己也没太搞清 1.5 三维建筑模型 CIM中三维建筑模型主要表达建(构)筑物的空间位置.几何形态及外观效果等. 在建筑相关 ...

  8. 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!

    效果 来具体介绍之前先来看看效果. 使用C#构建了一个简单的MCP客户端,以下为运行这个简单客户端的截图,同样可以在Cline等其它的一些MCP客户端中玩耍. 创建一个数据库表: 获取数据库中的所有表 ...

  9. k8s dashboard token 生成/获取

    创建示例用户 在本指南中,我们将了解如何使用 Kubernetes 的服务帐户机制创建新用户.授予该用户管理员权限并使用与该用户绑定的承载令牌登录仪表板. 对于以下每个和的代码片段ServiceAcc ...

  10. JavaScript的标准库

    Object 对象 概述 JavaScript 的所有其他对象都继承自Object对象,即那些对象都是Object的实例. Object对象的原生方法分成两类:Object本身的方法与Object的实 ...