搬果实
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+3),也就是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; }