题目描述
说明
NOIP 2006 提高组 第一题
这题也是一题区间DP哦
下文先贴出代码,会按照代码来讲解思路
#include<iostream> #include<cstdio> #include<cstring> using namespace std; long long R[300],L[300],N,F[300][300],Ans;//R[]为头标记 ,L[]为尾标记 inline void Read(void) { scanf("%lld",&N); for(int i=1; i<=N; ++i) { scanf("%lld",&R[i]); L[i-1]=R[i];//前一个珠子尾标记 为此个珠子的头标记 R[i+N] =R[i];//存环成链 L[i-1+N]=L[i-1]; } L[N*2]=R[1]; } inline void Work(void) { for(int n=1; n<N; ++n)//确定合并 { for(int i=1; i<=N*2-n; ++i) //确定起点,PS:注意i的循环条件,笔者就是在这里卡了十分钟!!! { int j=i+n;//确定终点 for(int k=i; k<j; ++k)//确定中转点 { long long T=R[i]*R[k+1]*L[j]; F[i][j]=max(F[i][j],F[i][k]+F[k+1][j]+T);//从第i颗珠子到第j颗珠子的最佳聚合结果 } if(F[i][j]>Ans)Ans=F[i][j]; } } } int main(void) { Read(); Work(); printf("%lld",Ans); return 0; }
思路解析:
1.首先和石子合并的方法一样,先存环成链;
2.根据题意,本题的初始化条件为F[i][j]=0,因而根据c++的特点,不用再进行初始化
3.动态转移方程的书写:F[i][j]=max(F[i][j],F[i][k]+F[k+1][j]+R[i]*R[k+1]*L[j]);
即求合并第 i-k 个珠子和第 k+1-j 个珠子所释放的能量最大值(具体分析此次就不在详解了,如若不明请看:[NOI1995]石子合并)
4.比较问题结果最优值
恭喜你AC了!!!