能量项链 (区间DP)
能量项链 (区间DP)
问题引入
思路
诸如此类不能线性规划的问题要用到区间DP,区间DP一般就是三层循环,第一层表示区间长度(本题即\(n\)),第二层枚举起点并根据第一层区间长度算出区间终点,第三层便在当前区间内枚举决策(即哪两个合并)
本题由于是环,还需破环为列,可以开两倍大的数组,即\(a[i]=a[i+n]\),便可在第n颗珠子时求到第1颗珠子的头标记(也即第n颗珠子的尾标记)
合并珠子即合并左珠\(dp[i][k]\)和右珠\(dp[k+1][j]\),释放能量\(a[i]*a[k+1]*a[j+1]\)(注意\(a[i]\)存放的是第i颗珠子的头标记,所以\(a[k+1]\)才是第k个珠子的尾标记)
例码
#include <iostream>
#define MAXN 202
#define MAX(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,a[MAXN],dp[MAXN][MAXN],ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i],a[i+n]=a[i];
for(int len=2;len<=n;len++)//枚举区间长度
for(int i=1;i+len-1<n*2;i++){//枚举区间起点
int j=i+len-1;//区间终点
for(int k=i;k<j;k++)//枚举决策
dp[i][j]=MAX(dp[i][j], dp[i][k]+dp[k+1][j]+a[i]*a[k+1]*a[j+1]);
}
for(int i=1;i<=n;i++)//枚举可能的答案
ans=MAX(dp[i][i+n-1],ans);
cout<<ans;
return 0;
}