hdu3506 Monkey Party--区间dp & 石子归并 & dp四边形优化

来源:互联网 发布:尚学堂java视频下载 编辑:程序博客网 时间:2024/06/05 07:15

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3506


题意:石子归并问题。用到了dp四边形优化:http://blog.csdn.net/u014800748/article/details/45750737


在一个圆形操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。
规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。


开始以为通过贪心算法可能很快解决问题,可是是行不通的。

首先我们可以把这么堆石子看成一列

我们假如5堆的石子,其中石子数分别为7,6,5,7,100


      •按照贪心法,合并的过程如下:
        每次合并得分
        第一次合并  7  6   5   7    100   =11
      第二次合并  7   11     7   100=18
      第三次合并  18    7    100 =25
        第四次合并   25   100 =125


        总得分=11+18+25+125=179


       •另一种合并方案
        每次合并得分
     第一次合并  7  6   5   7    100   ->13
         第二次合并  13   5     7   100->12
         第三次合并  13    12    100 ->25
         第四次合并   25   100 ->125


         总得分=13+12+25+125=175

#define _CRT_SECURE_NO_DEPRECATE #include<iostream>#include<vector>#include<cstring>#include<queue>#include<stack>#include<algorithm>#include<cmath>#define INF 99999999#define eps 0.0001using namespace std;int n;int s[2005][2005];int dp[2005][2005];int sum[2005][2005];int main(){while (~scanf("%d", &n)){for (int i = 0; i <= 2 * n + 1; i++)for (int j = 0; j <= 2 * n + 1; j++)dp[i][j] = INF;for (int i = 1; i <= n; i++){scanf("%d", &sum[i][i]);sum[i + n][i + n] = sum[i][i];s[i][i] = i;dp[i][i] = dp[i + n][i + n] = 0;s[i + n][i + n] = i + n;}for (int i = 1; i <= 2 * n; i++)for (int j = i + 1; j <= 2 * n; j++)sum[i][j] = sum[i][j - 1] + sum[j][j];for (int l = 1; l <= 2 * n; l++){for (int i = 1; i + l <= 2 * n; i++){int j = i + l;for (int k = s[i][j - 1]; k <= s[i + 1][j]; k++){if (dp[i][j] > dp[i][k] + dp[k + 1][j] + sum[i][j]){dp[i][j] = dp[i][k] + dp[k + 1][j] + sum[i][j];s[i][j] = k;}}}}int ans = INF;for (int i = 1; i <= n; i++)ans = min(ans, dp[i][i + n - 1]);printf("%d\n", ans);}return 0;}







1 0
原创粉丝点击