现在有n堆石子,第i堆有ai个石子。现在要把这些石子合并成一堆,每次只能合并相邻两个,每次合并的代价是两堆石子的总石子数。求合并所有石子的最小代价。
Input
第一行包含一个整数T(T<=50),表示数据组数。
每组数据第一行包含一个整数n(2<=n<=100),表示石子的堆数。
第二行包含n个正整数ai(ai<=100),表示每堆石子的石子数。
Output
每组数据仅一行,表示最小合并代价。
Sample Input
2
4
1 2 3 4
5
3 5 2 1 4
Sample Output
19
33
思路:dp[i][j]表示第i堆石子合并到第j堆石子需要的最小代价
那么可以得到递推式:dp[i][j]=min( dp[i][j], dp[i][k] + dp[k+1][j] +sum)
其中i<=k<j, sum表示i-j石子的总数量,可用sum[j]-sum[i]表示,sum数组为前缀和数组
AC代码:
#include<iostream>
using namespace std;
#define N 105
#define inf 0x3f3f3f3f
int dp[N][N];
int sum[N];
int main()
{
int t,n;
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&sum[i]);
sum[i]+=sum[i-1]; //求出前缀和
}
for(int len=1;len<=n;len++) //枚举区间长度
{
for(int i=1;i+len<=n;i++) //注意不能越界
{
int j=i+len;
dp[i][j]=inf;
for(int k=i;k<j;k++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
}
}
cout<<dp[1][n]<<endl;
}
return 0;
}