Sicily1345(能量项链DP)

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值