luogu P1880 [NOI1995]石子合并

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/smmyy022/article/details/81943575

题解

第一次遇到区间dp的问题,这种解构问题的方法还是比较新颖的。
既然是dp,我们还是想要把全部的状态以及选择表达出来,怎样表示是个问题。

大概思路是

//mst(dp,0) 初始化DP数组
for(int i=1;i<=n;i++)
{
    dp[i][i]=初始值
}
for(int len=2;len<=n;len++)  //区间长度
for(int i=1;i<=n;i++)        //枚举起点
{
    int j=i+len-1;           //区间终点
    if(j>n) break;           //越界结束
    for(int k=i;k<j;k++)     //枚举分割点,构造状态转移方程
    {
        dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);
    }
}

ps: 这道题按这种思路是 O(n^3)的复杂度,还可以进一步优化。(平行四边形优化)


Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

int n,m;
int cot[202],pre[202];
int f1[202][202],f2[202][202];
int d(int i,int j){
    return pre[j] - pre[i-1];
}
int main(){

    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>cot[i];
        cot[i+n] = cot[i];
    }
    for(int i=1;i<=n+n;i++) pre[i] = pre[i-1]+cot[i];

    for(int len=1;len<n;len++){
        for(int i=1,j=i+len;i<n+n && j< n+n;i++,j=i+len){// 环成链 i要迭代到n后面
            f2[i][j] = 1e9;
            for(int k=i;k<j;k++){
                f1[i][j] = max(f1[i][j], f1[i][k]+f1[k+1][j]+d(i,j));
                f2[i][j] = min(f2[i][j], f2[i][k]+f2[k+1][j]+d(i,j));
            }
        }
    }

    int maxp,minp;
    maxp=0,minp=99999999;
    for(int i=1;i<=n;i++){
        maxp = max(maxp,f1[i][i+n-1]);  
        minp = min(minp,f2[i][i+n-1]);  
    }

    cout<<minp<<endl<<maxp<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/smmyy022/article/details/81943575