源代码: #include<cstdio> #include<algorithm> using namespace std; int n,Sum[401],f1[401][401],f2[401][401]; int main() //注意在本题中,f1[][]与f2[][]的作用进行了调换。 { scanf("%d",&n); for (int a=1;a<=n;a++) for (int b=1;b<=n;b++) f1[a][b]=f2[a][b]=1000000000; //奇怪的范围错误,看来以后遇到DP尽量手动赋值。 for (int a=1;a<=n;a++) { int t; f2[a][a]=0; scanf("%d",&t); Sum[a]=Sum[a-1]+t; //前缀和。 } for (int a=1;a<n;a++) f1[a][a+1]=Sum[a+1]-Sum[a-1]; //预处理只有两堆。 for (int k=3;k<=n;k++) for (int a=1;a<=n-k+1;a++) { int t=a+k-1; for (int b=a;b<t;b++) f2[a][t]=min(f2[a][t],f1[a][b]+f2[b+1][t]+Sum[t]-Sum[b]); for (int b=a;b<t;b++) f1[a][t]=min(f1[a][t],f2[a][b]+f2[b+1][t]+Sum[t]-Sum[a-1]); } printf("%d",f2[1][n]); return 0; } /* 做题还是要灵活转化。 60分做法: 在石子归并2的基础上改一改,断点变为两个,则有状态转移方程: f[i][j]=min{f[i][k1]+f[k1+1][k2]+f[k2+1][j]+S[j]-S[i-1]} 时间复杂度为O(n^4); 100分做法: 在60分做法上优化就可以了,设辅助数组f2[i][j]=min{f1[i][k]+f1[k][j]},则有: f1[i][j]=min{f2[i][k]+f1[k+1][j]+S[j]-S[i-1]} 并列的O(n^3)时间复杂度。 做DP时应考虑转化以前做过的DP,并在此基础上进行修改和优化。 */