zoukankan      html  css  js  c++  java
  • P1880 [NOI1995]石子合并

    联系:区间DP

    P1880 [NOI1995]石子合并

    题解

    可以算区间DP板子题啦

    注意这是个石子圈

           如果最初的第 L 堆和第 R 堆石子被合并成一堆,那么就说明 L~R 之间的每堆石子也被合并了,这样L和R才有可能相邻

           所以任意一堆石子可以用闭区间 [ L , R ] 表示,表示这堆石子是由最初的 L~R 堆石子合并来的,那么在这个区间的石子被合并之前一定存在一个合并点 K 使得 [ L , K ] 和 [ K+1,R] 先被合并,然后这两堆再被合在一起啊

            也就是一个长区间是由两个更小的区间转移来的,合并点 k 就是决策,所以就把区间长度当做状态

            sum[ i ] 从第1堆到第 i 堆石子的总和

    fmaxn[ i ][ j ] 合并第 i~j 堆石子的最大得分 ,初始化为0

     fminn[ i ][ j ] 合并第 i~j 堆石子的最小得分 ,初始化为0x7f (一个很大的值)

     

    状态转移方程:

    fmaxn[ i ][ j ] = max( fmaxn[ i ][ j ] , fmaxn[ i ][ k ] + fmaxn[ k+1 ][ j ] ) + ( sum[ j ] - sum[ i-1 ] )

     fminn[ i ][ j ] = min( fminn[ i ][ j ] , fminn[ i ][ k ] + fminn[ k+1 ][ j ] ) + ( sum[ j ] - sum[ i-1 ] )

    断点K:要从合并的区间内部枚举   i<=K<j

    处理石子环:

            假设他是一条链,扩展2倍,第 i 堆石子等于第 i+n 堆石子,然后对这 2n 堆进行维护,枚举 f(1,n) ,f(2,n+1),,,f(n,2n-1) ,取最优值

    时间复杂度: O(8n3

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    int n;
    int stone[205],sum[205];
    int fmaxn[205][205],fminn[205][205];
    int ansmin=0x7fffffff,ansmax=0;
    
    int main()
    {
    
        memset(fmaxn,0,sizeof(fmaxn));
        memset(fminn,0x7f,sizeof(fminn));  //敲黑板!!!初始化大值 
        n=read();
        for(int i=1;i<=n;i++)
        {
            stone[i]=read();
            stone[i+n]=stone[i];
        }
        
        for(int i=1;i<=2*n;i++)
        {
            sum[i]=sum[i-1]+stone[i];
            fmaxn[i][i]=0;  //自己到自己的合并为0 
            fminn[i][i]=0;
        }
        
        for(int l=2;l<=n;l++)  //外层枚举区间长度 
           for(int i=1;i<=2*n-l+1;i++)  //起点 
           {
               int j=i+l-1;  //终点 
               for(int k=i;k<j;k++)  //断点 
            {
                fmaxn[i][j]=max(fmaxn[i][j],fmaxn[i][k]+fmaxn[k+1][j]);
                fminn[i][j]=min(fminn[i][j],fminn[i][k]+fminn[k+1][j]);
            } //左右合并取最优 
            
            fmaxn[i][j]+=(sum[j]-sum[i-1]); //最后加上合并左右的花费 
            fminn[i][j]+=(sum[j]-sum[i-1]);
            
           }
        
        //二倍区间延长取最优 
        for(int i=1;i<=n;i++) ansmin=min(ansmin,fminn[i][i+n-1]);
        for(int i=1;i<=n;i++) ansmax=max(ansmax,fmaxn[i][i+n-1]);
        
        printf("%d
    ",ansmin);
        printf("%d
    ",ansmax);
        
        return 0;
    }
    石子合并代码
  • 相关阅读:
    mp3播放时间
    图片生成视频
    语音合成服务
    360p以上
    实现文字转语音功能
    字幕格式
    音频格式
    视频格式
    微信发朋友圈 -- 群营销素材同步
    FourCC
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/11130289.html
Copyright © 2011-2022 走看看