原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3506
题意:石子归并问题。用到了dp四边形优化:http://blog.youkuaiyun.com/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.0001
using 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;
}