• 石子合并问题


    石子合并问题它有三种分类。。。

    1、给出N堆石子,要将N堆石子合并成一堆,规定:每次任意合并两堆石子,花费为合并后的石子个数,求合并为一堆石子的最多或最少花费。

    这是最简单的情况,直接贪心,每次取最小的两堆石子合并,就能得到答案。类似oj上的23940。

    2、给出N堆石子线性排成一列,要将N堆石子合并成一堆,规定:每次合并相邻两堆石子,花费为合并后的石子个数,求合并为一堆石子的最多或最少花费。

    这种就比较复杂点,如果你看过矩阵连乘,你会发觉很相似。所以我们类似地用矩阵连乘的递推方式,就可以得到它的状态转移方程:设dp[ i ] [ j ]为第 i 堆石子到 j 堆石子合并的最优值,sum[ i ][ j ]为第 i 堆石子到第 j 堆石子的总和。

    0 (i = j)

    即 dp[ i ][ j ]={ min ( dp[ i ][ k ] +dp[ k+1 ][ j ]+sum[ i ][ j ] ) (i != j)

    其代码实现


    3、第三种就是在第二种的基础上,将线性改成环形排列。。。。
    其思想分析跟第二种是差不多的,但他是环形的,就意味他不只是1 2 3 4 这样合并,还可以4 1 2 3这样取。不难发现,其实解法类似。不过由于是环形,我们要在每次相加只有都对个数取余数,以防止数组越界。

    0 j==0;

    dp[ i ] [ j ]={​min( dp[ i] [ k ]+dp[ (k + i+1)% n][ j - k- 1]+sum[ i ][ j ] ) j 〉0

    ​ 重点记住:不过,此处的j与前面(2)中的j意义并不一样,此处的j意义为:从第i堆出发,往下数j堆石子。而且sum的取法有些不一样,例如,总共5堆石子,从第四堆后取4堆石子,就分为两部分去取:4-5,1-2 去取。但要记住sum和dp都一样,第一维记录的是起点,第二维代表的是从起点后取合并多少堆石子。

    代码如下:

    #include<bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define MAX 205
    int dp1[MAX][MAX];
    int dp2[MAX][MAX];
    int p[MAX];
    int n;
    using namespace std;
    int getsum(int i,int j){//求第 i 堆起,取j 堆的sum。
         if(i+j<n){
          int k;
           if(i==0)
            k=0;
         else
            k=p[i-1];
         return p[i+j]-k;
         }
         else
            return getsum(0,i+j-n)+getsum(i,n-i-1);//分两部份。
    }
    void itin(){//初始化,最小子问题。
       for(int i=0;i<n;i++){
        dp1[i][0]=0;
        dp2[i][0]=0;
       }
    }
    int main(void){
       scanf("%d",&n);
                 itin();
            int x;
            for(int i=0;i<n;i++){//前i堆和。
                scanf("%d",&x);
                if(i==0)
                  p[i]=x;
                else
                    p[i]=p[i-1]+x;
            }
            for(int i=0;i<n;i++){
                dp1[i][i]=0;
                dp2[i][i]=0;
            }
            for(int j=1;j<n;j++)//枚举长度。
              for(int i=0;i<n;i++){
                int temp=getsum(i,j);
           //  printf("%dok
    ",temp);
                    dp1[i][j]=INF;
                    dp2[i][j]=-1;
                for(int k=0;k<j;k++){
                    dp1[i][j]=min(dp1[i][j],dp1[i][k]+dp1[(i+k+1)%n][j-k-1]+temp);//递推取最优。
                    dp2[i][j]=max(dp2[i][j],dp2[i][k]+dp2[(i+k+1)%n][j-k-1]+temp);
                }
            }
            int mi=dp1[0][n-1];
            int ma=dp2[0][n-1];
       for(int i=0;i<n;i++){//枚举起点找最优。
            mi=min(dp1[i][n-1],mi);
            ma=max(dp2[i][n-1],ma);
       }
       printf("%d %d
    ",mi,ma);
    }
    

      

  • 相关阅读:
    黑马程序员——JAVA基础之主函数main和静态static,静态代码块
    黑马程序员——JAVA基础之final this.和super.的区别
    黑马程序员——JAVA基础之构造函数,构造代码块
    黑马程序员——JAVA基础之简述 类的封装
    黑马程序员——JAVA基础之简述面向对象,类,变量,匿名对象
    NBU Rman异机恢复Oracle
    Oracle的Rman差异增量备份
    rman备份出现ORA-19625
    查询rman备份信息常用指令
    RMAN-06172: no AUTOBACKUP found or specified handle is not a valid copy or piece
  • 原文地址:https://www.cnblogs.com/linhaitai/p/9127621.html
Copyright © 2020-2023  润新知