分果实问题

搬果实

Time Limit:1000MS  Memory Limit:65536K
Total Submit:968 Accepted:118

Description

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆,只有相邻的两堆可以合并。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过N-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

Input

输入包括两行,第一行是一个整数N(1 <= N <= 100),表示果子的种类数。第二行包含N个整数,用空格分隔,每个整数M(1 <= M <= 200)是第M种果子的数目。

Output

包括一行,这一行只包含一个整数,也就是最小的体力耗费值。

Sample Input

 

3
1 2 9

 

Sample Output

 

15

 

思路解析:

先用数组arr[ ]储存果子的数量

利用区域dp我们创建一个数组dp[i][j],i代表从第几堆开始,j代表到第几堆结束,用这个数组来储存最优解

然后我们可以想:

当只有一堆的时候,就是i=j  :  那么合并时就是这堆的值dp[i][j]=arr[i]

当有两堆的时候 : 就是这两堆的和

当有三堆的时候 : 比如  1  2  9,那么就是两种方法,先是1  2合并变成 3  9,然后在3和9合并,这样的总和就是(1+2)+(1+2+9),也就是dp[1][2]+sum  ( 这里k是一个结点,需要从i循环到j,然后sum表示i到j的总和 )。还有一种就是2和9先合并,然后合并1和11,这样就是dp[2][3]+sum

 

所以当有n堆的时候,可以利用k从i循环到j

 

所以得出状态转移方程:

 

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int sum[101];
int arr[101];
int dp[101][101];
int n;
int get_Ans()
{
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n-i; j++)
		{
			int v = i + j;
			int temp = sum[v] - sum[j - 1];
			dp[j][v] = 2000;
			for (int k = j; k <= v; k++)
			{
				dp[j][v] = min(dp[j][v], dp[j][k] + dp[k + 1][v] + temp);
			}
		}
	}
	/*for (int i = 1; i <= n; i++)
	{
		for (int j = i + 1; j <= n; j++)
		{
			int temp = sum[j] - sum[i - 1];
			dp[i][j] = 2000;
			for (int k = i; k <= j; k++)
			{
				dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + temp);
			}
		}
	}
	return dp[1][n];*/
}
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> arr[i];
		sum[i] = sum[i - 1] + arr[i];
	}
	cout << get_Ans() << endl;
	system("pause");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值