石子归并(区间dp模板题)

现在有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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43693379/article/details/90725092