题意:按次序给出一串环状数字,每次选取相邻俩数字将其合并成一个数字并将得到的数字计入总值,求出可以得到的最大总值和最小总值
解法:区间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; }