51nod 1021石子归并 dp

Love The Way You Lie 2022-08-20 13:11 301阅读 0赞

N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。

例如: 1 2 3 4,有不少合并方法

1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)

1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)

1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)

括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。

想了很久只想出一种三重循环的方法,不过题目给出的n<=100,三重也是很快就过了的。

我们用dp[i][j]表示合并i到j之间的元素所需要的最大代价,那么很快就可以想到递推公式了。

dp[i][j] = min(dp[i][i+1]+dp[i+2][j],dp[i][i+2][i+3][j],…dp[i][j-2]+dp[j-1][j]) + a[i]+…a[j]

其中我们可以先利用sum[i]来记录a[1]+a[2]+…+a[i]的值。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. int const maxn = 105;
  8. int a[maxn];
  9. int sum[maxn]; //sum[i] = a[1]+a[2]+...+a[i];
  10. int dp[maxn][maxn];//dp[i][j]表示的是合并i到j之间的元素的最大代价,其中j>i
  11. int main()
  12. {
  13. int n ;
  14. while(scanf("%d",&n)!=EOF)
  15. {
  16. memset(sum,0,sizeof(sum));
  17. memset(dp,0,sizeof(dp));
  18. for(int i = 1 ; i <= n ; i++)
  19. {
  20. scanf("%d",&a[i]);
  21. sum[i]=sum[i-1]+a[i];
  22. }
  23. for(int k = 1 ; k <= n ; k++)
  24. {
  25. for(int i = 1 ; i+k <= n ; i++)
  26. {
  27. int j = k+i ;
  28. dp[i][j] = dp[i+1][j] + sum[j]-sum[i-1];
  29. for(int num = i ; num < j ; num++)
  30. {
  31. dp[i][j] = min(dp[i][j],(dp[i][num]+dp[num+1][j]+sum[j]-sum[i-1]));
  32. }
  33. //cout<<dp[i][j]<<endl;
  34. }
  35. }
  36. printf("%d\n",dp[1][n]);
  37. }
  38. return 0;
  39. }

发表评论

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

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

相关阅读

    相关 51nod 1021石子归并 dp

    N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。

    相关 51nod1021石子归并(区间dp

    题意:N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。