题目描述 Description
有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。
题解:
经典的
O(n3)
相信谁都会,但是本题需要用到四边形不等式优化到
O(n2)
。四边形不等式适用于以下形式的DP方程:
f[i][j]=min{f[i][k]+f[k+1][j]}+w[i][j]
,而且
w
需要满足对于
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=3010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int f[Maxn][Maxn],sum[Maxn],s[Maxn][Maxn];
int main()
{
memset(f,63,sizeof(f));
int n=read();sum[0]=0;
for(int i=1;i<=n;i++)
{
int x=read();
sum[i]=sum[i-1]+x;
f[i][i]=0;s[i][i]=i;
}
for(int l=2;l<=n;l++)
for(int i=1;i+l-1<=n;i++)
{
int j=i+l-1,w,cost=sum[j]-sum[i-1];
for(int k=s[i][j-1];k<=s[i+1][j];k++)
{
if(f[i][k]+f[k+1][j]+cost<f[i][j])
{
s[i][j]=k;
f[i][j]=f[i][k]+f[k+1][j]+cost;
}
}
}
printf("%d",f[1][n]);
}