目录
原题:
题目描述:
有N堆石子排成一圈,其中第i堆的石子的重量为,现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆合并成新的一堆,形成的新石子堆的重量以及消耗的体力都是两堆石子的重量之和。
求把全部N堆石子合并成一堆最少需要消耗多少体力。
输入格式:
第一行一个正整数N(N<=300),表示石子的堆数N。
第二行N个正整数,表示每堆石子的质量(<=1000)。
输出格式:
一个正整数,表示最少需要消耗多少体力。
样例输入:
4
1 3 5 2
样例输出:
20
题目大意:
给你一个环,让你你合并相邻两个元素,代价为这两个元素的和,直到只剩一个元素为止,问你最小代价是多少。
主要思路:
首先,这是一道环形dp的板子题,我们需要破环成链,就把这个数组复制一遍,对于样例复制一遍就是:1,3,5,2,1,3,5,2。接下来就是普通的区间dp了,用三重循环:第一层是从1~n,代表长度,接下来就是左端点,分割端点。最后再找最小值时还要再循环一遍,找从i到i+n-1中的最小值。
转移方程:
注意事项:
注意下标问题。
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[610];
int dp[610][610];
int sum[610];
int main()
{
memset(dp,0x3f,sizeof(dp));
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i+n] = a[i];//数组扩倍
}
for(int i=1;i<=2*n;i++)//初始化
{
dp[i][i] = 0;
sum[i] = sum[i-1]+a[i];
}
for(int len=2;len<=n;len++)//枚举长度
{
for(int l=1;l+len-1<=2*n;l++)//右边界最多2*n
{
int r=l+len-1;
for(int i=l;i<r;i++)
{
dp[l][r] = min(dp[l][r],dp[l][i]+dp[i+1][r]+sum[r]-sum[l-1]);
}
}
}
int ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)//找最小值
{
ans = min(ans,dp[i][i+n-1]);
}
cout<<ans;
return 0;
}