当前位置:   article > 正文

【算法实验四】--【动态规划】--石子合并_实验四石子合并

实验四石子合并

1148.石子合并

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

在一个圆形操场的四周摆放着n堆石子(n<= 100),现要将石子有次序地合并成一堆。规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。编一程序,读入石子堆数n及每堆的石子数(<=20)。选择一种合并石子的方案,使得做n-1次合并,得分的总和最小; 比如有4堆石子:4 4 5 9 则最佳合并方案如下:
4 4 5 9 score: 0
8 5 9 score: 8
13 9 score: 8 + 13 = 21
22 score: 8 + 13 + 22 = 43

 

输入

可能有多组测试数据。 当输入n=0时结束! 第一行为石子堆数n(1<=n<=100); 第二行为n堆的石子每堆的石子数,每两个数之间用一个空格分隔。

 

输出

合并的最小得分,每个结果一行。

 

输入样例

4 4 4 5 9 0

 

输出样例

43

解析:这个题,,我原以为它是和矩阵连乘乘积的那个题一样,后来发现有两点不同。第一点是对于矩阵连乘的题目,num=arr[i][k]+arr[k+1][j]+row[i]*col[k]*col[j],这里一个新的arr的数是两个子项代价加起来,然后再加这两个子项算的代价,而这个摆石子是算的两个子项加起来,然后再加这两个的和。。。好吧我有点卡住了,我不知道怎么把以前的代价加进去。

像矩阵连乘那样,把对角线都设为0,算当前节点m [ i ] [ j ] 时,取其中间节点h , 然后算m[i[[j]=m[i][h]+m[h+1][j]+x,这个x为把这两个子节点连起来的代价,矩阵连乘是将 i , h , j 的维数乘起来,这里的话,应该是将当前两堆直接加起来,举个例子,如:

对于数据7,3,4,8,其产生的矩阵就应该为:

0       10      21      43            

0       0        7        22                   

0       0        0        12

0       0        0         0

上面为第一次算法后,第一次的m[i][j]就等于stone[i]+stone[j],当进行到m[1][3]和m[2][4]时,如m[1][3]=min( m[1][1]+m[2][3]+stone[1]+stone[2]+stone[3] ,m[1][2]+m[3][3]+stone[1]+stone[2]+stone[3]),m[2][4]=min( m[2][2]+m[3][4]+stone[2]+stone[3]+stone[4] ,m[2][3]+m[4][4]+stone[1]+stone[2]+stone[3] )。

事实证明,写博客有利于整理思路!啊哈哈哈,详见代码:

  1. #include <iostream>
  2. #include<stdio.h>
  3. #include<string.h>
  4. using namespace std;
  5. int n;
  6. int stone[100];
  7. int m[100][100],s[100][100];//s是记录路径的
  8. int num(int m,int n)
  9. {
  10. int res=0;
  11. for(int i=m;i<=n;i++)
  12. res+=stone[i];
  13. return res;
  14. }
  15. int main()
  16. {
  17. while(~scanf("%d",&n)&&n)
  18. {
  19. memset(stone,0,sizeof(stone));
  20. memset(m,0,sizeof(m));
  21. memset(s,0,sizeof(s));
  22. for(int i=1;i<=n;i++)
  23. {
  24. cin>>stone[i];
  25. }
  26. for(int r=1;r<n;r++)
  27. {
  28. for(int i=1;i<=n-r;i++)
  29. {
  30. m[i][i+r]=m[i][i]+m[i+1][i+r]+num(i,i+r);
  31. s[i][i+r]=i;
  32. int j;
  33. for(j=i+1;j<i+r;j++)
  34. {
  35. if(m[i][j]+m[j+1][i+r]+num(i,i+r)<m[i][i+r])
  36. {
  37. m[i][i+r]=m[i][j]+m[j+1][i+r]+num(i,i+r);
  38. s[i][i+r]=j;
  39. }
  40. }
  41. }
  42. }
  43. cout<<m[1][n]<<endl;
  44. /*
  45. for(int i=1;i<=n;i++)
  46. {
  47. for(int j=1;j<=n;j++)
  48. cout<<m[i][j]<<" ";
  49. cout<<endl;
  50. }
  51. */
  52. }
  53. return 0;
  54. }

不过上面这个是仿照矩阵连乘写的,本题中石子是环形的,那么那个n维矩阵每一个元素都要用到了,循环里面也需加一点东西就可以。那么对于主层循环,

for(int r=1;r<n;r++)
        {
            for(int i=1;i<=n-r;i++)
            {
                m[i][i+r]=m[i][i]+m[i+1][i+r]+num(i,i+r);
                s[i][i+r]=i;
                for(int j=i+1;j<i+r;j++)
 间隔r自然是从1到n-1不变的,对于每一个开头的 i,应该改为 i<=n 即可,算法是m[i][(i+r)%n],既可以是m[1][3],也可以是m[3][1],且这两种算法是不同的,对应的 j 应该是1 2 3和3 4 1,用统一来表示就要取余,详见代码:

  1. #include <iostream>
  2. #include<stdio.h>
  3. #include<string.h>
  4. using namespace std;
  5. int n;
  6. int stone[100];
  7. int m[100][100],s[100][100];//s是记录路径的
  8. int num(int s,int t)
  9. {
  10. int res=0;
  11. if(s<=t)
  12. {
  13. for(int i=s;i<=t;i++)
  14. res+=stone[i];
  15. }
  16. else
  17. {
  18. for(int i=s;i<n;i++)
  19. res+=stone[i];
  20. for(int i=0;i<=t;i++)
  21. res+=stone[i];
  22. }
  23. return res;
  24. }
  25. int main()
  26. {
  27. while(~scanf("%d",&n)&&n)
  28. {
  29. memset(stone,0,sizeof(stone));
  30. memset(m,0,sizeof(m));
  31. memset(s,0,sizeof(s));
  32. for(int i=0;i<n;i++)
  33. {
  34. cin>>stone[i];
  35. }
  36. for(int r=1;r<n;r++)
  37. {
  38. for(int i=0;i<n;i++)
  39. {
  40. m[i][(i+r)%n]=m[i][i]+m[(i+1)%n][(i+r)%n]+num(i,(i+r)%n);
  41. s[i][(i+r)%n]=i;
  42. int k=r-1;
  43. for(int j=(i+1)%n;k>=0;j=(j+1)%n,k--)
  44. {
  45. if(m[i][j%n]+m[(j+1)%n][(i+r)%n]+num(i,(i+r)%n)<m[i][(i+r)%n])
  46. {
  47. m[i][(i+r)%n]=m[i][j%n]+m[(j+1)%n][(i+r)%n]+num(i,(i+r)%n);
  48. s[i][(i+r)%n]=j;
  49. }
  50. }
  51. }
  52. }
  53. int x=1000;
  54. for(int i=0;i<n;i++)
  55. {
  56. if(m[i][(i+n-1)%n]<x)
  57. x=m[i][(i+n-1)%n];
  58. }
  59. cout<<x<<endl;
  60. }
  61. return 0;
  62. }

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/509926
推荐阅读
相关标签
  

闽ICP备14008679号