P1063 [NOIP2006 提高组] 能量项链
考察:区间dp
思路:
根据题目我们可以发现,当相邻两颗珠子合并时,只剩下首尾,中间部分不关心.
我们回顾一下区间dp,f[l][r]表示将[l,r]区间内的石子合并(以模板题为例),中间是什么我们也不关心,而f数组求最值是以某个分割点k来划分集合.
f[l][r] = max(f[l][k]+f[k][r],f[l][r]) 这里的分割点k,也是将[l,r]划分为[l,k][k,r]两个区间.
那么这道题也可以用区间dp做.根据题目发现我们需要将4与1连在一起,但是将4,1连在一起还是不够,我们发现(4,1)的新珠子还可以和2融合.所以这里我们需要断环成链,构造2倍长度的a数组.最后答案是以某点i为起点,区间长度为n取max
本题的转移方程f[l][r] = max(f[l][k]+f[k][r]+a[l]*a[k]*a[r],f[l][r]) 融合是三个不同点融合,因此k不能与l,r相同. a[l]*a[k]*a[r]就是将[l,k][k,r]看成一个珠子.
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 const int N = 210; 5 int a[N],f[N][N],n; 6 int main() 7 { 8 scanf("%d",&n); 9 for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i+n] = a[i]; 10 for(int len=3;len<=2*n;len++) 11 for(int l=1;l+len-1<=2*n;l++) 12 { 13 int r = l+len-1; 14 for(int k=l+1;k<r;k++) 15 f[l][r] = max(f[l][k]+f[k][r]+a[l]*a[k]*a[r],f[l][r]); 16 } 17 int ans = 0; 18 for(int i=1;i<=n;i++) ans = max(ans,f[i][i+n]); 19 printf("%d\n",ans); 20 return 0; 21 }
总结:
区间dp只考虑首尾,常常以枚举断点来划分集合.