DP经典题型:石子合并问题

本周集训专题为DP系列,一个经典的系列便是石子归并问题。

(1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小(或最大)。

这是石子归并的简化版本,石子处于一排。由于发现只能是相邻的2堆石子进行归并。我们会发现,贪心算法在此处便失去作用,局部最优解并不能带来整体最优解。

因此,不难让我们想到,此题应该采取DP(dynamic Programing)来求其最优解。

动态规划常常采取从部分整体最优解的拆分来得到最优解法的递归式,我们可以想到,此处是由2堆石子合并,所以最终最优解肯定是由两个局部最优解的加上整体的和求得。

因此,我们可以推断出动态转移方程:

dp[i][j]在此处表示从第i堆加到第j堆的最优解,而当i == j是,并不存在相加,所以结果为0.

(2)将上述问题从一排改为环形,便是完整版本的石子合并问题了。

不难发现,其实解法类似。不过由于是环形,我们要在每次相加只有都对个数取余数,以防止数组越界。

不过,此处的j与前面(1)中的j意义并不一样,此处的j意义为:从第i堆出发,往下数j堆石子。因此,j == 0时,自然dp[i][j] == 0了

因为j的意义不同,所以dp[i][j]长得自然不一样了,实际上还是一个意思。

所以sum[i][j]也改为:

附上求最小值的代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <limits>
 4 using namespace std;
 5 const int INF = INT_MAX;
 6 const int maxn = 1003;
 7 int dp[maxn][maxn];
 8 int stone[maxn];
 9 int sum[maxn]; //0 - i 的和
10 int n; //本次的个数
11 int getSum(int i, int j) {
12     if (i + j >= n)
13         return getSum(i, n - i - 1) + getSum(0, i + j - n);
14     else
15         return sum[i + j] - (i > 0 ? sum[i - 1] : 0);
16 }
17 int findMin() {
18     for (int i = 0; i < n; i++) {
19         dp[i][0] = 0;
20     }
21     for (int j = 1; j < n; j++) {
22         for (int i = 0; i < n; i++) {
23             dp[i][j] = INF;
24
25             for (int k = 0; k < j; k++) {
26                 dp[i][j] = min(dp[i][j], dp[i][k] + dp[(i + k + 1) % n][j - k - 1] + getSum(i, j));
27             }
28         }
29     }
30     return dp[0][n - 1];
31 }
32
33 int main() {
34     while (cin >> n) {
35         for (int i = 0; i < n; i++) {
36             cin >> stone[i];
37             sum[i] = 0;
38         }
39         sum[0] = stone[0];
40         for (int i = 1; i < n; i++) {
41             sum[i] = sum[i - 1] + stone[i];
42         }
43         cout << findMin() << endl;
44     }
45     return 0;
46 }

                                                      

Vane_Tse On the Road.      2014-07-10   10:04:43

 

DP经典题型:石子合并问题,布布扣,bubuko.com

时间: 2024-10-05 04:09:27

DP经典题型:石子合并问题的相关文章

区间DP理解 (石子合并)

设有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,总代价为4+9+11=24,如果第二步是先合并2,3堆,则代

【dp】关于石子合并的O(nlogn)做法 GarsiaWachs算法

P5569 题意: 在一个操场上摆放着一排 \(N\) 堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的 \(2\) 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 试设计一个算法,计算出将 \(N\) 堆石子合并成一堆的最小得分. 数据范围: \(N≤40000,a_i≤200\) 题解: \(GrasiaWachs\) 算法 从左往右找,找到第一个 \(k\) ,使得 \(a[k-1]<=a[k+1]\) ,我们把这两堆石子合并,把代价加在 \(sum\) 上 然后从

区间DP [NYOJ 737] 石子合并(一)

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

[NYIST737]石子合并(一)(区间dp)

题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=737 很经典的区间dp,发现没有写过题解.最近被hihocoder上几道比赛题难住了,特此再回头重新理解一遍区间dp. 这道题的题意很明确,有一列石子堆,每堆石子都有数量,还有一个操作:相邻两堆石子合并成一堆石子,这个操作的代价是这两堆石子的数目和.要找一个合并次序,使得代价最小,最终输出最小代价. 这个题可以用动态规划,简单分析可以得知,这一列石子堆都可以划分为小区间,每个小区间

石子合并(四边形不等式优化dp)

该来的总是要来的———————— 经典问题,石子合并. 对于 f[i][j]= min{f[i][k]+f[k+1][j]+w[i][j]} From 黑书 凸四边形不等式:w[a][c]+w[b][d]<=w[b][c]+w[a][d](a<b<c<d) 区间包含关系单调: w[b][c]<=w[a][d](a<b<c<d) 定理1:  如果w同时满足四边形不等式和决策单调性 ,则f也满足四边形不等式 定理2:  若f满足四边形不等式,则决策s满足 s[i

石子合并问题(一) (基础的区间dp)

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

石子合并(区间dp)

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

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

好方啊马上就要区域赛了连DP都不会QAQ 毛子青<动态规划算法的优化技巧>论文里面提到了一类问题:石子合并. n堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 求出将n堆石子合并成一堆的最小得分和最大得分以及相应的合并方案. 设m[i,j]表示合并d[i..j]所得到的最小得分. 状态转移方程: 总的时间复杂度为O(n3). [优化方案] 四边形不等式: m[i,j]满足四边形不等式 令s[i,j]=max{k | m[

石子合并【环形DP】

先放上luogu的石子合并题目链接 这是一道环形DP题,思想和能量项链很像,在预处理过程中的手法跟乘积最大相像. 用一个m[][]数组来存储石子数量,m[i][j]表示从第 i 堆石子到第 j 堆石子的总数. 接下来三重循环 i 表示合并操作的起始位置, j 表示合并操作的终点,也就是把 i 到 j 合并 k表示间断点,即 i 到 j 合并过程中选择k点来作为合并位置 状态转移方程 f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+m[i][k]+m[k+1][j]);