51nod 1022 石子归并 V2 —— DP四边形不等式优化

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022

 

基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
 收藏
 关注
N堆石子摆成一个环。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
 
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
 
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
 
Input
第1行:N(2 <= N <= 1000)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
Output
输出最小合并代价
Input示例
4
1
2
3
4
Output示例
19
 
 
题解:
1. 一开始想到的是:dp[l][r] = min(dp[l][k]+dp[k+1][r]+w[l][r]), l<=k<r 的区间DP,但时间复杂度为O(n^3),而n<=1e3,所以无法通过。
2. 然后需要四边形不等式进行优化,四边形不等式优化DP的结论请看:传送门
3. 优化后:dp[l][r] = min(dp[l][k]+dp[k+1][r]+w[l][r]), s[l][r-1]<=s[l][r]<=s[l+1][r],即s[l][r-1]<=k<=s[l+1][r]
 
w[][]数组需要满足满足的条件:
1) 区间包含单调性:被包含的区间的值小于等于包含的区间的值。
2) 四边形不等式:交叉区间之和小于等于被包含区间加包含区间的值
 
 
 
代码如下:
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 2e3+10;
18 
19 int dp[MAXN][MAXN], sum[MAXN], w[MAXN][MAXN], s[MAXN][MAXN];
20 int main()
21 {
22     int n;
23     while(scanf("%d", &n)!=EOF)
24     {
25         sum[0] = 0;
26         for(int i = 1; i<=n; i++)   //因为初始时为环(而非一行),所以复制多一份到后面,
27             scanf("%d",&sum[i]), sum[n+i] = sum[i];
28 
29         for(int i = 1; i<2*n; i++)  //求前缀和
30             sum[i] += sum[i-1];
31 
32         for(int l = 1; l<2*n; l++)  //求出每一段区间,最后一次合并所花费的代价(必为质量和)
33         for(int r = l; r<2*n; r++)
34             w[l][r] = sum[r]-sum[l-1];
35 
36         for(int i = 1; i<2*n; i++)  //初始化单位区间
37             dp[i][i] = 0, s[i][i] = i;
38 
39         for(int len = 2; len<=n; len++) //递推
40         for(int l = 1; l+len-1<2*n; l++)
41         {
42             int r = l+len-1;
43             dp[l][r] = INF;
44             for(int k = s[l][r-1]; k<=s[l+1][r]; k++)
45                 if(dp[l][r]>dp[l][k]+dp[k+1][r]+w[l][r])    //四边形不等式优化
46                 {
47                     dp[l][r] = dp[l][k]+dp[k+1][r]+w[l][r];
48                     s[l][r] = k;
49                 }
50         }
51         int ans = INF;
52         for(int l = 1; l<=n; l++)   //枚举起点,取最小值
53             ans = min(ans, dp[l][l+n-1]);
54         printf("%d\n", ans);
55     }
56 }
View Code

 

 

  

 

 

posted on 2018-04-02 21:42  h_z_cong  阅读(224)  评论(0编辑  收藏  举报

导航