洛谷p1775石子合并(弱化版)

题目链接: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=<k<=j,

dp[i][j]=min(dp[i][k]+dp[k+1][j])+sum[i][j]。

这里是不是有些不理解?我会在代码中把注释标注完善

参考代码:

 1 #include<bits/stdc++.h>
 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<n;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<j;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<<minval()<<endl;
34     return 0;
35     
36 }

 

posted @ 2022-02-15 21:41  江上舟摇  阅读(183)  评论(0编辑  收藏  举报