码迷,mamicode.com
首页 > 其他好文 > 详细

51 Nod 1021 石子归并(dp)

时间:2017-10-07 20:40:59      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:stream   题目   归并   img   blog   blank   www.   www   mes   

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#problemId=1021&noticeId=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 }

 

51 Nod 1021 石子归并(dp)

标签:stream   题目   归并   img   blog   blank   www.   www   mes   

原文地址:http://www.cnblogs.com/Leonard-/p/7635633.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!