【题目大意】
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分。
【思路解析】
首先是断环为链,这题数据不大,没什么问题。
说一下转移方程吧$$f[l][r]=min(f[l][r],f[l][k]+f[k+1][r])+sum[r]-sum[l-1](l\le k<r)$$初始值:详见代码
目标:$min(f[i][i+n-1])(i\in[1,n]),max(g[i][i+n-1])(i\in[1,n])$.
还有就是要注意一下循环嵌套的顺序,哪一个循环在里面,哪一个循环在外面。
【代码实现】
1 #include<bits/stdc++.h> 2 #define rg register 3 #define go(i,a,b) for(rg int i=a;i<=b;i++) 4 #define back(i,a,b) for(rg int i=a;i>=b;i--) 5 #define mod 2147483648 6 #define ll long long 7 using namespace std; 8 const int N=102<<1; 9 int n,a[N],sum[N]; 10 ll f[N][N],g[N][N]; 11 int main(){ 12 scanf("%d",&n); 13 memset(f,0x3f,sizeof(f));memset(g,0,sizeof(g)); 14 go(i,1,n) scanf("%d",&a[i]),a[i+n]=a[i]; 15 go(i,1,n*2) f[i][i]=0,g[i][i]=0,sum[i]=sum[i-1]+a[i]; 16 go(len,2,n) go(l,1,2*n-len+1){ 17 int r=l+len-1; 18 go(k,l,r-1){ 19 f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]); 20 g[l][r]=max(g[l][r],g[l][k]+g[k+1][r]); 21 } 22 f[l][r]+=sum[r]-sum[l-1]; 23 g[l][r]+=sum[r]-sum[l-1]; 24 } 25 ll ans1=123456798,ans2=0; 26 go(i,1,n) ans1=min(ans1,f[i][i+n-1]),ans2=max(ans2,g[i][i+n-1]); 27 printf("%lld\n%lld\n",ans1,ans2); 28 return 0; 29 }