1022 石子归并 V2
基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
N堆石子摆成一个环。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
Input
第1行:N(2 <= N <= 1000)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
Output
输出最小合并代价
Input示例
4
1
2
3
4
Output示例
19
普通的DP很容易就能够想到: fi,j 表示从第 i 堆石子合并到第 j 颗石子的最小代价是什么,只要枚举间接点 k 就能够轻松转移。但是发现一个很重要的问题,时间高达 n3 ,问题就在于如何优化 k 的枚举。
这里就要引进一种DP优化方式:四边形不等式优化。设a<b<c<d,若 fa,c+fb,d≤fb,c+fa,d 则满足四边形不等式。
这道题设 gi,j 表示对应 i,j 最优状态的 k 值,可以发现 gi,j 是满足四边形不等式的。
1、 gi,1≤gi,2≤......≤gi,n−1≤gi,n
2、 g1,i≤g2,i≤......≤gn−1,i≤gn,i
稍微转化一下就能够弄出关于 gi,j 的关系式: gi,j−1≤gi,j≤gi+1,j ,因为所有 k 的枚举个数和是n,所以总时间复杂度是 n2 。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int f[2001][2001],n,i,j,k,x,g[2001][2001],a[1001],s[2001],ans;
int main(){
scanf("%d",&n);
s[0]=0;
fo(i,1,n){
scanf("%d",&a[i]);s[i]=s[i-1]+a[i];
}
fo(i,1,n){
s[i+n]=s[i+n-1]+a[i];
}
memset(f,127,sizeof(f));
fo(i,1,2*n){
g[i][i]=i;
f[i][i]=0;
}
fo(x,1,n){
fo(i,1,n*2-1){
j=i+x;
if(j>n*2-1)break;
fo(k,g[i][j-1],g[i+1][j])
if(f[i][k]+f[k+1][j]+s[j]-s[i-1]
f[i][j]=f[i][k]+f[k+1][j]+s[j]-s[i-1];
g[i][j]=k;
}
}
}
ans=0x7777777;
fo(i,1,n)ans=min(ans,f[i][i+n-1]);
printf("%d",ans);
}