洛谷P1063 能量项链
题目要求是求得一个最大的能量值,一个最优解。用动态规划做。
因为这是一个环形的手链,那么情况就比较复杂。但是我们可以复杂问题简单化,把环形的手链剪开,变成链形。比如:一条 2 3 5 10 的环状手链,可以从不同位置剪开,变成四条手链:(考虑首尾特殊情况)
- 2 3 5 10 2
- 3 5 10 2 3
- 5 10 2 3 5
- 10 2 3 5 10
其实就是 2 3 5 10 2 3 5 10 从第1、2、3、4位开始往后数5个数。
然后根据动态规划的特点,将大问题转化为小问题,利用子问题的答案结构化地计算大问题的答案。
我们先计算三个数能够汇聚的能量,比如 2 3 5 ,答案显而易见就是 2 * 3 * 5 = 30。
将所有三个数挨在一起能够汇聚出来的能量都算出来了之后,就可以利用三个数的能量计算四个数汇聚的能量,而不必重复计算。
比如 2 3 5 10 。 就有两种可能, 原本的 2 * 3 * 5 + 2 * 5 * 10 和 2 * 3 * 10 + 3 * 5 * 10,保留的那个值。
————
i 表示计算多少个数汇聚的能量。因为这里相当于是将环状的手链,拆分成了四条包含 5 个数的数列,所以 i 的最大值就是 5 ,最后从 保存结果的 f 数组中找到长度为 5 的数列能够汇聚的最大能量就可以了。(2 3 5 10 这个例子)
——————
在做这个题之前,可以先看看 石子合并题目链接非常类似的一个题。
#include <bits/stdc++.h>
using namespace std;
int n;
int a[201];
int f[201][201] = {0};
int ans = 0;
int main(){
cin>>n;
int i,j,k;
for(i=1;i<=n;i++){
cin>>a[i];
a[i+n] = a[i];
}
for(i=3;i<=n+1;i++){// 每次计算几个数
for(j=1;j<=2*n-i+1;j++){// 从第 j 个数开始
for(k=j+1;k<j+i-1;k++){// j k j+i-1
int m = f[j][k] + f[k][j+i-1];
f[j][j+i-1] = max(m+a[j]*a[k]*a[j+i-1],f[j][j+i-1]);
}
}
}
for(i=1;i<=n;i++){
ans = max(ans,f[i][i+n]);
}
cout<<ans;
return 0;
}