RQNOJ:PID5 能量项链

        题目说明:http://www.rqnoj.cn/problem/5

RQNOJ:PID5 能量项链_第1张图片

           很典型的一道DP题目,而且是一道区间DP题。解题的关键在于找出状态转移方程,解题的几个关键点如下:

  1. 题目序列可以认为是环状的(最后一个的尾元素对应第一个的头元素),考虑通过拷贝延长序列长度一杯,达到链状的效果。这里每个元素之后的连续N个元素就对应着一种序列了;
  2. 在序列的基础上要考虑的就是结合顺序了,定义dp[i][j]为取出第i个到第j个珠子对应的最大能量值,那么获得最大能量值的方法就是遍历i到j之间的所有元素,dp[i][j]=max(dp[i][k]+dp[k+1][j]+两部分结合的能量值),其中i<=k<=j。
  3. 我们定义head[i]、tail[i]分别表示第i个珠子的头标记和尾标记,那么上面的式子可以进一步演化为:dp[i][j]=max(dp[i][k]+dp[k+1][j]+head[i]*tail[k]*tail[j]),其中head[i]就是i到k个珠子结合后的头标记,tail[k]为i到k个珠子结合后的尾(它等于k+1到j个珠子结合后的头标记head[k+1]),tail[j]为k+1到j个珠子结合后的尾标记。
         依据以上的分析,给出参考代码:
//http://www.rqnoj.cn/problem/5 PID5 / 能量项链 ☆

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;
int N;
int head[205],tail[205];
int dp[205][205];

int func(int l,int r)
{
	if(l==r) return 0;
	if(dp[l][r]!=-1) return dp[l][r];

	int temp=0; 
	for(int i=l;i<=r-1;i++)
		temp=max(temp,func(l,i)+func(i+1,r)+head[l]*tail[i]*tail[r]);//状态转换方程
	dp[l][r]=temp;
	return temp;
}

int main()
{
	scanf("%d",&N);
	for(int i=1;i<=N;i++) //录入头元素
		scanf("%d",&head[i]);
	for(int i=1;i<=N-1;i++) //利用头元素赋值尾元素
		tail[i]=head[i+1];
	tail[N]=head[1];

	for(int i=1;i<=N;i++)//将环延长至链
	{
		head[i+N]=head[i];
		tail[i+N]=tail[i];
	}
	memset(dp,-1,sizeof(dp));//dp赋初值-1
	int ans=0;
	for(int i=1;i<=N;i++)
		ans=max(ans,func(i,i+N-1));
	printf("%d",ans);

	return 0;
}


你可能感兴趣的:(动态规划,RQNOJ)