码迷,mamicode.com
首页 > 其他好文 > 详细

P1880石子合并

时间:2019-10-12 18:44:52      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:pre   define   模型   长度   cout   eof   ace   noi   起点   

1995年的noi区间dp题,这道题AC耗时达到了数月。

有一道题叫做果子合并,也是求合并的最小花费,但是那个题是可以随便合并两堆,但是这个题只能合并相邻的两堆,并且是一个环。对于环的问题,我们一般可以特判i==1和i==n或者倍增转化成链的问题,长度为两倍的时候即可涵盖所有环的情况。meanwhile我们发现了一个问题,当前要合并的两堆一定是要重合的,所以转化到了区间的问题,然后每一个最优子结构的状态是由其中的两个小小最优子结构而转移来的,所以枚举分割点即可。这样就建立了区间dp的模型。要注意最后还要进行判断,因为起点是1~2n。

1.熟记这个区间dp模型,当成模板题

2.分析每一个状态是怎么来的

3.正确处理环的做法

代码

#include<bits/stdc++.h>
#define maxn 300
using namespace std;
int dpMin[maxn][maxn];
int dpMax[maxn][maxn];
int a[maxn];//石头数目 
int sum[maxn];//前缀和
int n; 
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i+n]=a[i];
    }
    for(int i=1;i<=n*2;i++){
        sum[i]=sum[i-1]+a[i];//前缀和
    }
    memset(dpMax,-1,sizeof dpMax);
    memset(dpMin,0x3f,sizeof dpMin);
    for(int i=1;i<=n*2;i++){
        dpMin[i][i]=0;
        dpMax[i][i]=0;
    }
    //区间DP 
    for(int len=2;len<=n;len++){
        for(int i=1;i<=n*2;i++){
            int j=i+len-1;
            if(j>2*n) break;
            for(int k=i;k<j;k++){
                dpMin[i][j]=min(dpMin[i][j],dpMin[i][k]+dpMin[k+1][j]+sum[j]-sum[i-1]);
                dpMax[i][j]=max(dpMax[i][j],dpMax[i][k]+dpMax[k+1][j]+sum[j]-sum[i-1]);
            }    
        }
    }
    int ansMax=dpMax[1][n];
    int ansMin=dpMin[1][n];
    for(int i=1;i<=n;i++){
        ansMax=max(dpMax[i][i+n-1],ansMax);
        ansMin=min(dpMin[i][i+n-1],ansMin);
    } 
    cout<<ansMin;    
    puts(" ");    
    cout<<ansMax;
    return 0;
}

 

P1880石子合并

标签:pre   define   模型   长度   cout   eof   ace   noi   起点   

原文地址:https://www.cnblogs.com/china-mjr/p/11663221.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!