洛谷p1880 石子归并

题目链接

题意:按次序给出一串环状数字,每次选取相邻俩数字将其合并成一个数字并将得到的数字计入总值,求出可以得到的最大总值和最小总值

解法:区间dp

因为数字为环状,所以通过在原串数字的尾端 加上一串原数字来线性模拟环状;

以i为区间首端,p为区间长度,可得区间尾端j=i+p-1,k表示两区间合并的分界点;

以求(i~j)区间最大值dp1[i][j]:(i~j)区间即由(i~k)区间与(k+1~j)区间合并而来

得其状态转移方程:dp1[i][j]=max(dp1[i][j],dp[i][k]+dp[k+1][j]+s[j]-s[i-1]);s[j]-s[i-1]为(i~j)区间的数字和即合并后需计入总值的数字;

#include<iostream>
#define N 10000000
using namespace std;
int n,a[205],s[205],dp1[205][205],dp2[205][205];
int minl=N,maxl;
int main(){
    cin>>n;
    for(int i=1;i<=n*2;i++)
        for(int j=1;j<=2*n;j++)
        dp2[i][j]=N;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i+n]=a[i];
        s[i]=s[i-1]+a[i];
        dp1[i][i]=0;
        dp1[i+n][i+n]=0;
        dp2[i][i]=0;
        dp2[i+n][i+n]=0;
        }
        for(int i=1;i<=n;i++) s[i+n]=s[i]+s[n];
        for(int p=2;p<=n;p++)
        for(int i=1;i<=2*n;i++){
         int j=i+p-1;
         for(int k=i;k<j&&j<=2*n;k++){
         dp1[i][j]=max(dp1[i][j],dp1[i][k]+dp1[k+1][j]+s[j]-s[i-1]);
         dp2[i][j]=min(dp2[i][j],dp2[i][k]+dp2[k+1][j]+s[j]-s[i-1]);
         }
        }
        for(int i=1;i<=n+1;i++){
            minl=min(minl,dp2[i][i+n-1]);
            maxl=max(maxl,dp1[i][i+n-1]);
        }
        cout<<minl<<endl<<maxl<<endl;
return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/WELOTX/p/11362587.html