标签:stream 题目 归并 img blog blank www. www mes
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#problemId=1021¬iceId=347826
题意:N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。
计算将N堆石子合并成一堆的最小代价。
题解:如果我们先把最小的两个数合起来,下一步我们是再合新的两个数,还是把一个新的数放进已经合起来的两个数里面,这样想起来就很复杂,是吧。
所以我们换一个思路,把所有相邻的两个数都合起来,在这个基础上我们去合三个数,因为已经有两个数合起来的基础了,我们只要比较是先合前面两个数再加上
第三个数代价少,还是先合后面两个数再加上第一个数代价少,然后取最少的。以此类推,以局部最优解推到全局最优解。
dp[i][j]代表i—j区间的最少代价,sum[i][j]代表i—j区间内全部合并的代价总值。状态转移方程:
1 #include <cstring> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 6 const int N=111; 7 const int INF=0x3f3f3f3f; 8 int num[N]; 9 int dp[N][N],sum[N][N]; 10 11 int main(){ 12 int n; 13 cin>>n; 14 for(int i=1;i<=n;i++) cin>>num[i]; 15 16 for(int i=1;i<=n;i++){ 17 for(int j=1;j<=n;j++){ 18 if(i==j) sum[i][j]=num[i],dp[i][j]=0; 19 else dp[i][j]=INF; 20 } 21 } 22 23 for(int k=1;k<n;k++){ //k+1个石子合并 24 for(int i=1;i+k<=n;i++){ //i代表起始位置 25 sum[i][i+k]=sum[i][i+k-1]+num[i+k]; 26 for(int j=i;j<i+k;j++){ 27 dp[i][i+k]=min(dp[i][i+k],dp[i][j]+dp[j+1][i+k]+sum[i][i+k]); 28 } 29 } 30 } 31 32 cout<<dp[1][n]<<endl; 33 return 0; 34 }
标签:stream 题目 归并 img blog blank www. www mes
原文地址:http://www.cnblogs.com/Leonard-/p/7635633.html