zoukankan      html  css  js  c++  java
  • Vijos 1038 添加括号 【区间DP】

    题目:
    给定一个正整数序列a(1),a(2),...,a(n),(1<=n<=20)
    不改变序列中每个元素在序列中的位置,把它们相加,并用括号记每次加法所得的和,称为中间和。

    例如:
    给出序列是4,1,2,3。

    第一种添括号方法:
    ((4+1)+(2+3))=((5)+(5))=(10)
    有三个中间和是5,5,10,它们之和为:5+5+10=20
    第二种添括号方法

    (4+((1+2)+3))=(4+((3)+3))=(4+(6))=(10)
    中间和是3,6,10,它们之和为19。

    现在要添上n-1对括号,加法运算依括号顺序进行,得到n-1个中间和,求出使中间和之和最小的添括号方法。如果有多组最优解,考虑将括号尽可能往前放

    输出3行。

    第一行,为添加括号的方法。

    第二行,为最终的中间和之和。

    第三行,为n-1个中间和,按照从左到右,从里到外的顺序输出。

    分析:

    这个题的第二问和合并石子没什么区别。

      在一个操场上一排地摆放着N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个程序,计算出将N堆石子合并成一堆的最小得分。

     

    对于第一问,肯定要记录括号在什么位置,我们采用递归+分治的思路,在计算最小值的时候,我们已经将区间( i , j )分成了两个子区间 ( i , p ) 和 ( p+1 , j ) ,于是枚举断点 p ,使得 f [ i ] [ j ] 最小,我们可以考虑,在每次更新 f [ i ] [ j ]时,都记录

    g [ i ] [ j ] = p 为区间 ( i , j ) 要分出的两个括号的中间,即为分界线,从而:

    输出 " ( "  ==>  输出 ( i , p )  ==> 输出 " + " ==> 再输出 ( p+1 , j ) ==> 输出 " ) "

    第三问同理。

    注意:在记录 g [ i ] [ j ] 时,若出现 f [ i ] [ j ] == f [ i ] [ p ] + f [ p+1 ] [ j ] +sum [ j ] - sum[ i-1 ] 要更新它,因为题中红色的字告诉我们,括号越往前越好,而通过调试,我们发现 g [ i ] [ j ] 的更新只能变大,不能变小(即断点只能往后) ,并且前一段分得越少,括号越早结束,因此 最前面的 " ((( x + y ) + ... " 就越少。因此我们要把断点尽量往后放。

    不明白的可以自己用下面的数据调试一下:(注意红字)

    输入:

    6
    1 3 2 1 1 1

    输出:

    加上 " = " :

    ((1+3)+((2+1)+(1+1)))
    23
    3 2 5 9

    不加:

    ((1+3)+(2+(1+(1+1))))
    23
    4 2 3 5 9

    下面是参考代码:

     
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int n,a[50],sum[50]={0};
    int ff[50][50],f[50][50]={0};
    void print_equa(int,int);
    void print_ans();
    void print_sum(int,int);
    int main()
    {
     cin>>n;
     for(int i=1;i<=n;i++)
     {
      cin>>a[i];
      sum[i]=sum[i-1]+a[i];  
     }
     memset(ff,0x3f,sizeof(ff));
     for(int i=1;i<=n;i++)
      ff[i][i]=0;
     for(int l=2;l<=n;l++)
      for(int i=1;i<=n-l+1;i++)
      {
       int j=i+l-1;
       for(int p=i;p<j;p++)
       {
        if(ff[i][j]>=ff[i][p]+ff[p+1][j]+sum[j]-sum[i-1])
        {
         ff[i][j]=ff[i][p]+ff[p+1][j]+sum[j]-sum[i-1];
         f[i][j]=p;     
        }
       }
      }
     print_equa(1,n);
     print_ans();
     print_sum(1,n);
     return 0;
    }
    void print_equa(int l,int r)
    {
     if(l==r)
     {
      cout<<a[l];
      return ;
     }
     cout<<"(";
     int k=f[l][r];
     print_equa(l,k);
     cout<<"+";
     print_equa(k+1,r);
     cout<<")";
    }
    void print_ans()
    {
     cout<<endl<<ff[1][n]<<endl;
    }
    void print_sum(int l,int r)
    {
     if(!f[l][r])
      return;
     int k=f[l][r];
     print_sum(l,k);
     print_sum(k+1,r);
     cout<<sum[r]-sum[l-1]<<" ";
    }
    View Code
  • 相关阅读:
    4.关于QT中的QFile文件操作,QBuffer,Label上加入QPixmap,QByteArray和QString之间的差别,QTextStream和QDataStream的差别,QT内存映射(
    PlSql加入数据库链接
    UserScan的处理流程分析
    第八十八题(金山笔试题,字符串移动)
    4Sum_leetCode
    LeetCode Add Binary
    Hibernate or JPA Annotation中BLOB、CLOB注解写法
    配置Nginx防止直接用IP訪问Webserver
    Java集合系列之TreeMap源代码分析
    使用Application Loader上传APP流程解读[APP公布]
  • 原文地址:https://www.cnblogs.com/linda-fcj/p/7206273.html
Copyright © 2011-2022 走看看