题目
题解
这个题目是个环形,我们可以拆换成链,把这个环拉直,然后变成一个长度为2*n的链,这样就可以覆盖环形时的所有情况了.
然后接下来就是区间dp
我们很难直接的找出先合并哪一些是最优的,然后举个例子
比如说总共有4堆石子 我们要将它们合并 那么合并的最后一步有哪几种方案
第一种 把第一堆和后三堆已合并完的合并起来
第二种 前两堆 和 后两堆 合并起来 ( 都指合并完)
第三种 前三堆 和 第四堆
也就是说对于一个区间[i,j] 我们可以枚举一个中间的点k , 找到最优的那一种
因为我们是从区间长度短的来获得长的所以我们需要枚举区间长度
下面结合代码看
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 320;
ll n,a[N],dp[N][N],fdp[N][N],pre[N]; // dp和fdp一样,一个维护最小一个最大
void solve(){
cin >> n;
for(int i=1;i<=n;i++) {
cin >> a[i];
a[i+n]=a[i]; //拆成a[2*n]
}
for(int i=1;i<=2*n;i++)
pre[i]=pre[i-1]+a[i]; // 维护前缀和 合并的时候要计算区间和
for(int len=2;len<=n;len++) //枚举长度
for(int i=1,j=i+len-1;j<=2*n;i++,j++) // 枚举起点
{
//i是左端点 ,j 是 右端点 dp[i][j] 就是合并[i,j]的最优
dp[i][j]=4e18;// 初始化
for(int k=i;k<j;++k) // //枚举中间点
{
//比较,找到最优
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+pre[j]-pre[i-1]);
fdp[i][j]=max(fdp[i][j],fdp[i][k]+fdp[k+1][j]+pre[j]-pre[i-1]);
}
}
ll ma=fdp[1][n],mi=dp[1][n];//环形,找到长度为n的区间的最优解
for(int i=1;i<=n;i++){
if(ma<fdp[i][n+i-1]) ma=fdp[i][n+i-1];
if(mi>dp[i][n+i-1]) mi=dp[i][n+i-1];
}
cout << mi <<'\n' << ma;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _ =1;
//cin >> _;
while(_--)solve();
}