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);
}
}