nyoj 737 石子合并(一)(区间dp)

爱被打了一巴掌 2024-02-17 20:53 156阅读 0赞

石子合并(一)

时间限制: 1000 ms | 内存限制: 65535 KB

难度: 3

描述

有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。

输入

有多组测试数据,输入到文件结束。
每组测试数据第一行有一个整数n,表示有n堆石子。
接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开

输出

输出总代价的最小值,占单独的一行

样例输入

  1. 3
  2. 1 2 3
  3. 7
  4. 13 7 8 16 21 4 18

样例输出

  1. 9
  2. 239

分析:区间dp求解:

状态方程: dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j]); //dp[i][j] 表示的是合并第i堆到第j堆的最小花费 ,sum[i][j]表示从i到j的石子数量,作为本次合并的开销,边界处理,dp[i][i]=0 (自己到自己,不用合并,最小开销为0嘛),其他清空均为 INF

AC代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. #define INF 100000000
  6. const int maxn=200+5;
  7. int a[maxn];
  8. int dp[maxn][maxn];
  9. int sum[maxn][maxn];
  10. int main(){
  11. int n;
  12. while(scanf("%d",&n)==1){
  13. for(int i=1;i<=n;i++)
  14. scanf("%d",&a[i]);
  15. for(int len=1;len<=n;len++){ //找到区间i to j的总和
  16. for(int i=1;i<=n-len+1;i++){
  17. int j=len+i-1;
  18. int t=i;
  19. int tmp=0;
  20. while(t<=j){
  21. tmp+=a[t];
  22. t++;
  23. }
  24. sum[i][j]=tmp;
  25. }
  26. }
  27. for(int i=1;i<=n;i++)dp[i][i]=0;
  28. for(int len=1;len<=n;len++){
  29. for(int i=1;i<=n-len+1;i++){ //起点
  30. int j=len+i-1; //终点
  31. if(i!=j)dp[i][j]=INF;
  32. for(int k=i;k<j;k++){
  33. dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j]);
  34. }
  35. }
  36. }
  37. printf("%d\n",dp[1][n]);
  38. }
  39. return 0;
  40. }

发表评论

表情:
评论列表 (有 0 条评论,156人围观)

还没有评论,来说两句吧...

相关阅读

    相关 石子合并问题 (区间dp

    石子合并问题是最经典的DP问题。首先它有如下3种题型: (1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的

    相关 282 石子合并区间dp

    1. 问题描述: 设有 N 堆石子排成一排,其编号为 1,2,3,…,N。每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。每次只能合并相邻的两