洛谷P1063 能量项链 断环为链+dp

把以前写的博客搬运过来……
题目链接:传送门
经典区间dp题,同时要用到断环为链的思想,断环为链在题目讲解里叙述
----------------------------------分割线---------------------------------------
子状态:
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示从第i颗到第j颗珠子合并后释放能量的最大值。

分析:
设这个区间的左端点为 j j j,右端点为 p p p
a a a为第 j j j颗到第 k k k颗珠子合并后释放的最大值,即 d p [ j ] [ k ] dp[j][k] dp[j][k],设 b b b d p [ k + 1 ] [ p ] dp[k+1][p] dp[k+1][p]。合并后增加了 a [ j ] ∗ a [ k + 1 ] ∗ a [ p + 1 ] a[j]*a[k+1]*a[p+1] a[j]a[k+1]a[p+1]。所以可以推出状态转移方程:
d p [ j ] [ p ] = m a x ( d p [ j ] [ p ] , d p [ j ] [ k ] + d p [ k + 1 ] [ p ] + a [ j ] ∗ a [ k + 1 ] ∗ a [ p ] dp[j][p]=max(dp[j][p],dp[j][k]+dp[k+1][p]+a[j]*a[k+1]*a[p] dp[j][p]=max(dp[j][p],dp[j][k]+dp[k+1][p]+a[j]a[k+1]a[p]

对断环为链的理解:
最后一个珠子的尾标记为第一颗珠子的头标记,构成了一条环。此时若用普通的判断容易出错(而且可能状态转移方程会很复杂)。
若将记录的数组开大两倍,则第 n + 1 , n + 2 , … … , 2 n n+1,n+2,……,2n n+1,n+2,,2n颗珠子分别与第 1 , 2 , … … , n 1,2,……,n 1,2,,n颗珠子是等价的。
于是 d p [ 2 ] [ n + 1 ] dp[2][n+1] dp[2][n+1]就表示第 2 2 2个珠子到第 n + 1 n+1 n+1个珠子合并后释放能量的最大值,即第一颗珠子和最后一颗珠子合并。

易错点:
第一层循环:应该枚举区间长度。
第二层循环:应该枚举区间的左端点的位置,并由左端点和长度算出右端点的位置。
第三层循环:应该枚举断点(将左边合并成的珠子与右边合并成的珠子合并)。
---------------------------------分割线--------------------------------------

代码:

#include<stdio.h>
#include<cstring>
using namespace std;
const int Size=605;
int a[Size];
int dp[Size][Size];	//dp[i][j] 从第i颗珠子到第j颗释放能量的最大值
int main() {
	int n,len,ans=0;
	scanf("%d",&n);
	len=n<<1;	//两倍长度
	for(int i=1; i<=n; i++)
		scanf("%d",&a[i]);
	for(int i=n+1; i<=len; i++)	//复制数组
		a[i]=a[i-n];
	int f,p;
	for(int i=2; i<len; i++) {	//枚举区间长度
		f=len-i+1;
		for(int j=1; j<f; j++) {	//枚举左端点
			p=i+j-1;	//算出右端点
			for(int k=j; k<p; k++) {
				int tmp=dp[j][k]+dp[k+1][p]+a[j]*a[k+1]*a[p+1];
				//合并释放的能量
				if(tmp>dp[j][p])	dp[j][p]=tmp;	//更新答案
			}
		}
	}
	//找出把前多少个珠子合并到最后的珠子是最优解
	for(int i=1; i<=n; i++)
		if(dp[i][i+n-1]>ans)
			ans=dp[i][i+n-1];	//更新答案
	printf("%d",ans);
	return 0;
}
/*
dp[j][p]=max(dp[j][p],dp[j][k]+dp[k+1][p]+a[j]*a[k+1]*a[p];
*/
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值