NOI 1995 合并石子 区间DP

题目

题目描述

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

4
4 5 9 4

输出样例#1:

43
54

分析

区间DP啦!

首先断环为链,把整个数组复制一遍。所以第一个要注意的就是数组大小。(必须都是两倍的MAXN,否则你就得到了Fast Runtime Error Transform的技能!)(我还RE了两次,貌似是题目的数据范围有更改但题面没有说明。)(你的好友AC率已下线)

然后开始DP乱搞写状态转移方程。区间DP的常规状态:dp[i][j]表示合并第i到第j个石子的最大/最小分数。状态转移方程就是:

dp[i][j] = min/max(dp[i][j], dp[i][k]+dp[i][k+1]+s[j]-s[i-1]);

(其中s是前缀和)

这个方程不难理解,其实就是i到k堆石子合并的分数加上k+1到j堆石子合并的分数再加上当前合并的分数(i到j的石子个数之和)。

但是不能像我一样愚蠢

我一开始把转移方程写成了

dp[i][j] = min/max(dp[i+1][j]+s[j]-s[i-1], dp[i][j-1]+s[j][i-1]);

居然没想到合并一堆石子可以是由两堆已经进行过合并的石子产生的。(愚蠢!)

程序

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN = 500 + 10;
 4 int n, stone[2*MAXN], mi[2*MAXN][2*MAXN], mx[2*MAXN][2*MAXN], s[2*MAXN];
 5 int main()
 6 {
 7     cin >> n;
 8     for (int i = 1; i <= n; i++)
 9         cin >> stone[i], stone[i+n] = stone[i];
10     for (int i = 1; i <= 2*n; i++)
11         s[i] = s[i-1] + stone[i];
12     for (int i = 2*n-1; i >= 1; i--)
13     {
14         for (int j = i+1; j < n+i; j++)
15         {
16             mi[i][j] = 0x3F3F3F3F;
17             for (int k = i; k < j; k++)
18             {
19                 mi[i][j] = min(mi[i][j], mi[i][k]+mi[k+1][j]+s[j]-s[i-1]);
20                 mx[i][j] = max(mx[i][j], mx[i][k]+mx[k+1][j]+s[j]-s[i-1]);
21             }
22         }
23     }
24     int ans1 = 0x3F3F3F3f, ans2 = 0;
25     for (int i = 1; i <= n; i++)
26         ans1 = min(ans1, mi[i][i+n-1]), ans2 = max(ans2,mx[i][i+n-1]);
27     cout << ans1 << endl << ans2 << endl;
28     return 0;
29 }

原文地址:https://www.cnblogs.com/OIerPrime/p/8436926.html

时间: 2024-12-19 04:15:07

NOI 1995 合并石子 区间DP的相关文章

合并石子 区间dp水题

合并石子 链接: nyoj 737 描述: 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值. tags:最基本的区间dp,这题范围小,如果n大一些,还是要加个平行四边行优化. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring&g

石子合并(区间dp)

石子合并(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值. 输入 有多组测试数据,输入到文件结束. 每组测试数据第一行有一个整数n,表示有n堆石子. 接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开 输出 输出总代价的最小值,

zjnu 1181 石子合并(区间DP)

Description 在操场上沿一直线排列着 n堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的两堆石子合并成新的一堆, 并将新的一堆石子数记为该次合并的得分.允许在第一次合并前对调一次相邻两堆石子的次序. 计算在上述条件下将n堆石子合并成一堆的最小得分. Input 输入数据共有二行,其中,第1行是石子堆数n≤100: 第2行是顺序排列的各堆石子数(≤20),每两个数之间用空格分隔. Output 输出合并的最小得分. Sample Input 3 2 5 1 Sample Out

nyoj 737 石子合并(区间DP)

737-石子合并(一) 内存限制:64MB 时间限制:1000ms 特判: No通过数:28 提交数:35 难度:3 题目描述: 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值. 输入描述: 有多组测试数据,输入到文件结束. 每组测试数据第一行有一个整数n,表示有n堆石子. 接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空

CH5301 石子合并【区间dp】

5301 石子合并 0x50「动态规划」例题 描述 设有N堆沙子排成一排,其编号为1,2,3,-,N(N<=300).每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为 1  3  5  2 我们可以先合并1.2堆,代价为4,得到4 5 2 又合并 1,2堆,代价为9,得到9 2 ,再合并得到11,总代价为

直线石子合并(区间DP)

石子合并 时间限制:1000 ms  |  内存限制:65535 KB 描述有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值和最大值. 输入有多组测试数据,输入到文件结束.每组测试数据第一行有一个整数n,表示有n堆石子.接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开 输出输出总代价的最小值以及最大值(中间以空格隔开)

石子合并问题 /// 区间DP oj2025

Description 在一个圆形操场的四周摆放着n堆石子.现要将石子有次序地合并成一堆. 规定每次只能选相邻的两堆石子合并成新的一堆,并将新得的这堆石子数记为该次合并的得分. 试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分. Input 输入的第一行是正整数n,1 ≤ n ≤100,表示有n堆石子围成环形. 第二行有n个数,分别表示每堆石子的个数. Output 输出的第一行中的数是最小得分:第二行中的数是最大得分. Sample Input 44 4 5 9 Sample O

石子合并 (区间DP)

一.试题在一个园形操场的四周摆放N堆石子(N≤100),现要将石子有次序地合并成一堆.规定每次仅仅能选相邻的两堆合并成新的一堆,并将新的一堆的石子数.记为该次合并的得分.编一程序.由文件读入堆数N及每堆的石子数(≤20).①选择一种合并石子的方案,使得做N-1次合并,得分的总和最小.②选择一种合并石子的方案,使得做N-1次合并.得分的总和最大. 比如,所看到的的4堆石子,每堆石子数(从最上面的一堆数起.顺时针数)依次为4594.则3次合并得分总和最小的方案:8+13+22=43得分最大的方案为:

合并沙子//区间dp

P1062 合并傻子 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 从前有一堆傻子,钟某人要合并他们~但是,合并傻子是要掉RP的...... 描述 在一个园形操场的四周站着N个傻子,现要将傻子有次序地合并成一堆.规定每次只能选相邻的2个傻子合并成新的一个傻子,并将新的一个傻子的RP数,记为该次合并的RP数.(合并方法与NOI1999石子合并(本题库的沙子合并)相同,请大家参考上题合并方法)将N个傻子合并成1个的最小RP数为RPn和最大RP数为RPx.钟