石子合并应该算是比较经典的问题了。 f(i,j) 表示区间 [i,j] 合并的最小代价, f(i,j)=min{f(i,k)+f(k+1,j)+sum(i,j)} 最裸的DP是 O(n3) ,利用四边形不等式优化可以做到 O(n2) ,但是对于这道题的数据范围还是不够,我们需要更优越的算法——GarsiaWachs算法 这个算法是 O(n2) ,但是是不严格的,那么在大多数情况下时间复杂度是接近 O(nlogn)
决策单调性O(n^2)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 1003 using namespace std; int f[N][N],val[N],n,sum[N],s[N][N]; int main() { freopen("a.in","r",stdin); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&val[i]); for (int i=1;i<=n;i++) sum[i]=sum[i-1]+val[i]; memset(f,127/3,sizeof(f)); for (int i=1;i<=n;i++) f[i][i]=0,s[i][i]=i; for (int l=2;l<=n;l++) { s[n-l+1][n]=n; for (int i=n-l+1;i>=1;i--) { int j=i+l-1; for (int k=s[i][j-1];k<=s[i+1][j];k++) { int tmp=f[i][k]+f[k+1][j]+sum[j]-sum[i-1]; if (tmp<f[i][j]) f[i][j]=tmp,s[i][j]=k; } } } printf("%d\n",f[1][n]); }