题目链接:https://www.luogu.com.cn/problem/P1775;
思路:(单列石子合并)
经典的区间dp,我们要考虑的是如何获得最小的代价,就可以用dp[i][j]来表示从第i堆石子到第j堆石子所付出的最小代价,sum[i]是从开始到i的石堆和
例如:
当两堆两堆合并的时候,我们可给出样例是3,2,4,5。那这样来说,最小代价就是(2+4)+(2+4+5),
那么可以这么理解:dp[1][2]=dp[1][1]+dp[2][2]+sum[2]-sum[0];
sum[2]-sum[0]是前缀和求法,可以理解为从区间0到区间2之间的数字和。
那么三堆合并也是如此,
我们给出如上样例,2可以与4合并,也可以与5合并
那么dp[1][3]=min(dp[1][1]+dp[2][3],dp[1][2]+dp[3][3])+sum[3]-sum[0];
推广 到第k堆,i=
dp[i][j]=min(dp[i][k]+dp[k+1][j])+sum[i][j]。
这里是不是有些不理解?我会在代码中把注释标注完善
参考代码:
1 #include
2 using namespace std;
3 int n;
4 int sum[310];//记录从开始到i的石子堆之和
5 int dp[310][310];//表示从i到j合并所付出的最小代价
6 int a[310];
7 int minval()
8 {
9 for(int len=1;len//区间长度,即i到j的长度
10 {
11 for(int i=1;i<=n-len;i++)//起点i,好好体会为什么是n-len,因为n-len就是终点
12 {
13 int j=i+len;i//终点j
14 dp[i][j]=INT_MAX;//标兵作用,求最小值要先把他的标兵定于为最大值
15 for(int k=i;k)
16 {
17 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);//它本身和从i到k所付出的代价加上从k到j的代价以及二者之间的石堆
18 }
19 }
20 }
21 return dp[1][n];//1--n所付出的最少代价
22 }
23 int main()
24 {
25 ios::sync_with_stdio(false);
26 cin>>n;
27 for(int i=1;i<=n;i++)
28 {
29 cin>>a[i];
30 sum[i]=sum[i-1]+a[i];//从i到j区间的和
31 dp[i][i]=0;//初始化表示从i到i不需要代价
32 }
33 cout<endl;
34 return 0;
35
36 }