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

原题链接: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
#include
#include
#include
#include
#include
#include
#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;
}







你可能感兴趣的:(【动态规划】--高级DP)