拿石子合并这题为例
设mid[i][j]是dp[i][j]的最优解的断点,即它左区间的右端点,那么mid[i][j-1]<=mid[i][j]<=mid[i+1][j],所以在求解dp[i][j]时,枚举k可以只枚举这两个值之间枚举就好,
程序要先枚举区间长度,在枚举左端点,枚举每个区间长度时,他们的k总是只从1到n,只走一遍,所以这就相当于优化了一层,变成了O(n2)的。
比如len长度为3时,dp[1][3]只会枚举mid[1][2]-mid[2][3],如上。然后dp[2][4]时,枚举mid[2][3]-mid[3][4]。以此类推。
数据变大了,n^3过不了,考虑四边形优化
code:
#include <iostream> #include <cstdio> using namespace std; #define M 3003 #define INF 0x7fffffff int n,f[M][M],sum[M][M],st[M],mid[M][M]; int main() { cin>>n; for(int i=1; i<=n; i++) scanf("%d",&st[i]); for(int i=1; i<=n; i++) { f[i][i]=0; mid[i][i]=i; sum[i][i]=st[i]; for(int j=i+1; j<=n; j++) sum[i][j]=sum[i][j-1]+st[j]; } for(int len=2; len<=n; len++) { for(int i=1; i<=n-len+1; i++) { int j=i+len-1; f[i][j]=INF; for(int k=mid[i][j-1]; k<=mid[i+1][j]; k++) { if(f[i][j]>f[i][k]+f[k+1][j]+sum[i][j]) { f[i][j]=f[i][k]+f[k+1][j]+sum[i][j]; mid[i][j]=k; } } } } printf("%d ",f[1][n]); return 0; }