zoukankan      html  css  js  c++  java
  • 11078 不能移动的石子合并(优先做)

    11078 不能移动的石子合并(优先做)

    时间限制:1000MS  内存限制:1000K
    提交次数:0 通过次数:0

    题型: 编程题   语言: G++;GCC;VC

     

    Description

    做如下两个模型的石子合并,如下模型石子都不能移动出列,且合并都仅发生在相邻两堆石子中:
    
    (1)第一个模型:一行排列且相邻合并
    有n堆石子A1,A2,...,An形成一行,每堆石头个数记为ai(1<=i<=n),相邻两堆可合并,合并的分值为新堆的
    石子数。求合并为一堆的最低得分和最高得分。
    
    (2)第二个模型:一圈排列且相邻合并
    有n堆石子A1,A2,...,An形成首位相连的一个环形,An和A1相邻,每堆石头个数记为ai(1<=i<=n),相邻两堆
    可合并,合并的分值为新堆的石子数。求合并为一堆的最低得分和最高得分。
    
    例如4堆石子,每堆石子个数:9 4 4 5
    若排成一行,最小分值:(4+4)+(8+5)+(9+13)=43,最大分值:(9+4)+(13+4)+(17+5)=52。
    若排成圈状,最小分值:(4+4)+(8+5)+(9+13)=43,最大分值:(9+5)+(14+4)+(18+4)=54。
    
    此题以第一模型的最低得分为例,很多同学想着采用总是从最小的相邻两堆下手的思想,认为最后获得的也就是最
    低得分。但这个贪心策略是不对的。如下反例:
    
    石子:9 4 6 1 5
    
    贪心策略:
    9 4 6 6      计分6
    9 10 6       计分10
    9 16         计分16
    25           计分25
    得分共计:6+10+16+25=57
    
    但9 4 6 1 5 若如下方式合并:
    13 6 1 5     计分13
    13 6 6       计分6
    13 12        计分12
    25           计分25
    13+6+12+25=56
    
    或
    9 4 6 6      计分6
    9 4 12       计分12
    13 12        计分13
    25           计分25
    6+12+13+25=56
    
    后两种方式合并出的56都比贪心策略的57来的更低,因为总选择最小的相邻两堆去合并,并不能保证后续每步
    都可以最小,也许这轮最小导致后续几轮分值较大。
    




    输入格式

    两行。第一行n,第二行a1 a2 … an,每个ai(1<=i<=n)表示第i堆石子的个数,n<=100



    输出格式

    两行。第一行是第一个模型的最低得分和最高得分,中间空格相连,第二行是第二个模型的最低得分和
    最高得分,中间空格相连。



     

    输入样例

    4
    9 4 4 5



     

    输出样例

    43 52
    43 54



     

    提示

    (1)第一个石子合并模型
    
    和书上3.1节的矩阵连乘问题类似。假设m[i,j]为合并石子ai…aj,1<=i<=j<=n。所得到的最小
    得分,若没有“合并”这个动作,则为0。
    原问题所求的合并最小值即为m[1,n]。
    
    递推公式如下,其中min表示求最小,sum表示求和。
        m[i,j] = 0,   if i=j
        m[i,j] = min{ m[i,k]+m[k+1,j] | for all k, i<=k<j } + sum{ a(t) | for all t, i<=t<=j },
                      if i<j
    
    至于求最大值完全同理,自行推导递归公式。
    
    
    (2)第二个石子合并的环型模型
    
    方法一、环型模型完全可以转化为行型模型来求解。
    环形模型可视为等价的行形模型: A1 ... An A1 ... An-1,共2n-1堆,并在此行形模型中合并石头不超过
    链长n。
    环型模型问题所求,不是等价模型所填充的右上方元素m[1,2n-1],而是m[1,n], m[2,n+1], …, m[n,2n-1]
    这n个斜行元素中的最小值,
    即: min{ m[i, n+i-1] | for all i, 1<=i<=n }
    
    
    方法二、定义链,但环型定义链如果和前面行型一样,用链的起始和结束下标的话,不好定义,我们得换一
    种定义方式,加入链长这个参数而去掉结束下标这个参数。
    
    定义环型的链p(i,r),表示石头堆链Ai, A[(i+1)%n], ..., A[(i+r-1)%n]。  那链p(i,r)能够合并的最小分
    值记为m(i,r)。这里,1<=i<=n, 1<=r<=n。
    
    Ai  ...  A[(i+s-1)%n]    A[(i+s)%n]  ...  A[(i+r-1)%n]
    ---------------------    -----------------------------
          s个(链长s)                r-s个(链长r-s)
    
    最后一次合并在A[(i+s-1)%n]和A[(i+s)%n]之间,分为两个子链,左一个子链是p(i,s),右一个子链是p((i+s)%n, r-s)。
    链p(i,r)的最优值(最小值)由两个子链的最优值(最小值)得到。
    
       m(i,r) = 0     r=1;
       m(i,r) = min{ m(i,s)+m((i+s)%n, r-s) | for all s, 1<=s<r} + sum{a(t) | for all t, i<=t<=(i+r-1)%n }
                   1<r<=n
    
    由链长增加的方向来填充m(i,r)数组,原问题所求为: min{m(i,n) | 1<=i<=n}
    
    例如: n=5,  A1 A2 A3 A4 A5 构成环型。
    计算:
    r=1, m[i,1] (1<=i<=n), 即:m[1,1], m[2,1], m[3,1], m[4,1], m[5,1]。 
    对应的矩阵链为:A1, A2, A3, A4, A5;
    r=2, m[i,2] (1<=i<=n), 即:m[1,2], m[2,2], m[3,2], m[4,2], m[5,2]。 
    对应的矩阵链为:A1A2, A2A3, A3A4, A4A5, A5A1;
    r=3, m[i,3] (1<=i<=n), 即:m[1,3], m[2,3], m[3,3], m[4,3], m[5,3]。 
    对应的矩阵链为:A1A2A3, A2A3A4, A3A4A5, A4A5A1, A5A1A2;
    ......
    r=n, m[i,n] (1<=i<=n), 即:m[1,n], m[2,n], m[3,n], m[4,n], m[5,n]。 
    对应的矩阵链为:A1A2...An, A2A3...A1, A3A4...A2, A4A5...A3, A5A1...A4;
    
    对m二维数组一列一列填充,原问题所求环型的最小得分为最后填充的一列m元素:
    m[1,n], m[2,n], m[3,n], m[4,n], m[5,n]的最小值,即 min{m(i,n) | 1<=i<=n}。
    

    我的代码实现

      1 #include<stdio.h>
      2 
      3 #define N 1000
      4 int min[N][N],max[N][N];
      5 
      6 int sum(int p[],int i,int j){
      7     int t;
      8     int total=0;
      9     for(t=i;t<=j;t++){
     10         total+=p[t];
     11     }
     12     return total;
     13 }
     14 
     15 
     16 void MatrixChainMin1(int p[],int n){
     17     for(int i=1;i<=n;i++){
     18         min[i][i]=0;
     19     }
     20     for(int r=2;r<=n;r++){
     21         for(int i=1;i<=n-1;i++){
     22             int j=i+r-1;
     23             min[i][j]=min[i+1][j]+sum(p,i,j);    
     24                 for(int k=i+1;k<j;k++){
     25                     int t=min[i][k]+min[k+1][j]+sum(p,i,j);
     26                     if(t<min[i][j]){min[i][j]=t;}
     27                     }
     28             }
     29     }
     30 } 
     31 
     32 
     33 
     34 
     35 void MatrixChainMax1(int p[],int n){
     36     for(int i=1;i<=n;i++){
     37         max[i][i]=0;
     38     }
     39     for(int r=2;r<=n;r++){
     40         for(int i=1;i<=n-1;i++){
     41             int j=i+r-1;
     42             max[i][j]=max[i+1][j]+sum(p,i,j);
     43                 for(int k=i+1;k<j;k++){
     44                     int t=max[i][k]+max[k+1][j]+sum(p,i,j);
     45                     if(t>max[i][j]){max[i][j]=t;}
     46                     }
     47             }
     48     }
     49 } 
     50 
     51 
     52 void MatrixChainMin2(int p[],int n){
     53     for(int i=1;i<=n;i++){
     54         min[i][i]=0;
     55     }
     56     for(int r=2;r<=(n+1)/2;r++){
     57         for(int i=1;i<=n-1;i++){
     58             int j=i+r-1;
     59             min[i][j]=min[i+1][j]+sum(p,i,j);    
     60                 for(int k=i+1;k<j;k++){
     61                     int t=min[i][k]+min[k+1][j]+sum(p,i,j);
     62                     if(t<min[i][j]){min[i][j]=t;}
     63                     }
     64             }
     65     }
     66 } 
     67 
     68 void MatrixChainMax2(int p[],int n){
     69     for(int i=1;i<=n;i++){
     70         max[i][i]=0;
     71     }
     72     for(int r=2;r<=(n+1)/2;r++){
     73         for(int i=1;i<=n-1;i++){
     74             int j=i+r-1;
     75             max[i][j]=max[i+1][j]+sum(p,i,j);    
     76                 for(int k=i+1;k<j;k++){
     77                     int t=max[i][k]+max[k+1][j]+sum(p,i,j);
     78                     if(t>max[i][j]){max[i][j]=t;}
     79                     }
     80             }
     81     }
     82 } 
     83 
     84 
     85 
     86 int CircleMin(int n){
     87     int min1=min[1][n];
     88     for(int i=1;i<=n;i++){
     89         if(min1>min[i][n+i-1])min1=min[i][n+i-1];
     90 //        printf("%d ",min[i][n+i-1]);
     91     }
     92 //    printf("
    ");
     93     return min1;
     94 }
     95 
     96 int CircleMax(int n){
     97     int max1=max[1][n];
     98     for(int i=1;i<=n;i++){
     99         if(max1<max[i][n+i-1])max1=max[i][n+i-1];
    100 //        printf("%d ",max[i][n+i-1]);
    101     }
    102 //    printf("
    ");
    103     return max1;
    104 }
    105 
    106 
    107 int main(){
    108     int n;
    109     int p[N];
    110     scanf("%d",&n);
    111     for(int i=1;i<=n;i++){
    112         scanf("%d",&p[i]);
    113     }
    114     MatrixChainMin1(p,n);
    115     MatrixChainMax1(p,n);
    116     for(int i=1;i<=n-1;i++){
    117         p[n+i]=p[i];
    118     }
    119     MatrixChainMin2(p,2*n-1);
    120     MatrixChainMax2(p,2*n-1);
    121     printf("%d ",min[1][n]);
    122     printf("%d
    ",max[1][n]);
    123     printf("%d ",CircleMin(n));
    124     printf("%d",CircleMax(n));    
    125     return 0;
    126 }
  • 相关阅读:
    javaWeb学习总结(7)-会话之session技术
    javaWeb学习总结(6)- 会话之cookie技术
    javaWeb学习总结(5)- HttpServletRequest应用
    javaWeb学习总结(4)- HTML 关于head中的<meta>标签
    javaWeb学习总结(4)- HttpServletResponse
    javaWeb学习总结(3)- Servlet总结(servlet的主要接口、类)
    javaWeb学习总结(3)- Servlet基础
    java 上传3(uploadify中文api)
    java 上传2(使用java组件fileupload和uploadify)
    java 上传1(使用java组件fileupload)
  • 原文地址:https://www.cnblogs.com/double891/p/7859477.html
Copyright © 2011-2022 走看看