石子合并2 - 题目 - Daimayuan Online Judge
题意:
有 n堆石子围成一个圈,第 i堆石子有 ai颗,每次我们可以选择相邻的两堆石子合并,代价是两堆石子数目的和,现在我们要一直合并这些石子,使得最后只剩下一堆石子,问总代价最少是多少?
思路:
这道题是石子合并的升级版,但是也只不过加入了一个环形条件而已
1.对环形的处理:
倍增数组,然后在两倍长的区间中进行区间dp,最后枚举环取最小值即可
2.区间dp:
设计状态:
设f[i][j]为第i堆石子合并到第j堆石子所造成的最小代价
状态转移:
考虑该状态之前的最后一步决策:将最后两堆石子合并成最大的一堆石子
那么该状态就由这最后两堆石子合并而来
那么我们去枚举这两堆石子的边界k,其中 l<=k<r
合并两堆石子的代价就是所有石子的代价之和和两堆石子之前积累的代价之和
即f[i][j]=min(f[i][j],f[i][k],f[k+1][j])
Code:
#include <bits/stdc++.h>
const int mxn=5e2+10;
using namespace std;
int n,a[mxn],f[mxn][mxn],s[mxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[n+i]=a[i];
}
n*=2;
memset(f,127,sizeof(f));
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
for(int i=1;i<=n;i++) f[i][i]=0;
for(int i=1;i<n;i++){
for(int j=1;j+i<=n;j++){
for(int k=j;k<j+i;k++){
f[j][j+i]=min(f[j][j+i],f[j][k]+f[k+1][j+i]+s[j+i]-s[j-1]);
}
}
}
int ans=1<<30;
for(int i=1;i<=n/2-1;i++){
ans=min(ans,f[i][i+n/2-1]);
}
printf("%d\n",ans);
return 0;
}
总结:
1.对环形的处理:倍增数组