A[j][i]表示从j个珠子开始到j+i个珠子的能量最优值。(若j+i>=n-1则取余)
比如对于样例数据(2,3)(3,5)(5,10)(10,2)。
假定从0开始计,A[0][2]即(2,3)(3,5)(5,10)的最优值,可能先聚合(2,3)和(3,5),再(2,5)和(5,10)聚合,也可能(3,5)和(5,10)先聚合,再(2,3)和(3,10)聚合。
用A表示则为A[0][2]等于 A[0][1]+A[1][0]+(2,5)和(5,10)聚合释放的能量 或者 A[0][0]+A[1][1]+(2,3)和(3,10)聚合释放的能量 。
其中A[0][1]为之前已经先求出的(2,3)和(3,5)聚合的最优值,A[1][1]为之前先求出的(3,5)和(5,10)聚合的最优值。
因此可以先求出A[x][1]的所有值(0<=x<=n-1),再递推到A[x][n-1]。
当要求A[x][n-1]时,特别注意此时已经头尾相连,而我代码写的算法是以x为划分点的,即从x处将项链断开,没有考虑到x珠子和x之前的珠子合并的情况,
因此最后需要从0到n-1枚举一遍x,取最大的A[x][n-1]作为答案,因为枚举一遍之后则考虑了最终状态的所有合并情况。
同时当i==n-1时头尾合并时需要考虑用头部合并还是尾部合并,取释放能量最大的一种。
给出一组测试用例:
4
1 3 2 4
答案为84。
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <string> using namespace std; int A[105][105],B[105]; int main() { int n; while (scanf("%d",&n)!=EOF) { int i,j,k; for (i=0;i<=n-1;i++) scanf("%d",&B[i]); for (i=0;i<=n-1;i++) for (j=0;j<=n-1;j++) A[i][j]=0; for (i=1;i<=n-1;i++)//state i for (j=0;j<=n-1;j++)//pearl j for (k=0;k<=i-1;k++) if (i==n-1) { int maxx=max(B[j]*B[(j+k+1)%n]*B[j],B[(j+k+1)%n]*B[j]*B[(j+k+1)%n]); if (A[j][k]+A[(j+k+1)%n][i-k-1]+maxx>A[j][i]) A[j][i]=A[j][k]+A[(j+k+1)%n][i-k-1]+maxx; } else if (A[j][k]+A[(j+k+1)%n][i-k-1]+B[j]*B[(j+k+1)%n]*B[(j+i+1)%n]>A[j][i]) A[j][i]=A[j][k]+A[(j+k+1)%n][i-k-1]+B[j]*B[(j+k+1)%n]*B[(j+i+1)%n]; int maxx=0; for (i=0;i<=n-1;i++) if (A[i][n-1]>maxx) maxx=A[i][n-1]; printf("%d\n",maxx); } return 0; }
在数组后面接多一个重复数组来实现循环其实更简单一些:
// Problem#: 1345 // Submission#: 3042372 // The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License // URI: http://creativecommons.org/licenses/by-nc-sa/3.0/ // All Copyright reserved by Informatic Lab of Sun Yat-sen University #include <iostream> #include <cstdio> #include <cstring> using namespace std; int max(int a,int b) { return a>b?a:b; } int main() { int n,i,j,k; int a[205]; int dp[205][205]; while (scanf("%d",&n)!=EOF) { memset(dp,0,sizeof(dp)); for (i=0;i<n;i++) scanf("%d",&a[i]); for (i=n;i<2*n;i++) a[i]=a[i-n]; for (i=1;i<n;i++) for (j=0;j<2*n;j++) { int end=j+i; if (end>=2*n) continue; for (k=j;k<end;k++) dp[j][end]=max(dp[j][end],dp[j][k]+dp[k+1][end]+a[j]*a[end+1]*a[k+1]); } int maxn=0; for (i=0;i<n;i++) if (dp[i][i+n-1]>maxn) maxn=dp[i][i+n-1]; printf("%d\n",maxn); } }