洛谷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 }
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/15898236.html