https://www.cnblogs.com/violet-acmer/p/9852294.html
题解:
这道题是石子合并问题稍微升级版
这道题和经典石子合并问题的不同在于,经典的石子合并问题是一排,而此问题是一个圈,也就意味着最后一堆石子可已选择第一堆石子,那这要怎么做呢?
其实方法很简单,在n堆石子后额外增加(n-1)堆石子,这(n-1)堆石子不是随意造的,其个数与前(n-1)堆石子一一对应。
然后,就是经典的石子合并问题了。
对于 1 到 2*n-1堆石子,进行区间最优解的查找即可。
详情请看大佬博客:https://blog.csdn.net/u013512086/article/details/54565572
AC代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define INF 0x3f3f3f 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 const int maxn=200+50; 8 9 int n; 10 int a[maxn]; 11 int dp[maxn][maxn];//dp[i][j]:讲区间[i,j]堆石子合并所需的最小(或大)的花费 12 int sum[maxn];//前缀和 13 14 void Solve() 15 { 16 //求解最小花费 17 mem(dp,INF); 18 for(int i=1;i <= 2*n;++i) 19 dp[i][i]=0; 20 for(int len=2;len <= n;++len) 21 { 22 for(int i=1;i <= 2*n-len;++i) 23 { 24 int j=i+len-1; 25 for(int k=i;k < j;++k) 26 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); 27 } 28 } 29 int minRes=INF; 30 for(int i=1;i <= n;++i) 31 minRes=min(minRes,dp[i][i+n-1]); 32 printf("%d ",minRes); 33 //求解最大花费 34 mem(dp,0); 35 for(int len=2;len <= n;++len) 36 { 37 for(int i=1;i <= 2*n-len;++i) 38 { 39 int j=i+len-1; 40 for(int k=i;k < j;++k) 41 dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); 42 } 43 } 44 int maxRes=0; 45 for(int i=1;i <= n;++i) 46 maxRes=max(maxRes,dp[i][i+n-1]); 47 printf("%d ",maxRes); 48 } 49 int main() 50 { 51 scanf("%d",&n); 52 mem(sum,0); 53 for(int i=1;i <= n;++i) 54 scanf("%d",a+i),a[n+i]=a[i]; 55 for(int i=1;i <= 2*n;++i) 56 sum[i]=sum[i-1]+a[i]; 57 Solve(); 58 }