联系:区间DP
P1063 能量项链
题解
区间DP板子题
f[ i ][ j ] 从第 i 颗珠子到第 j 颗珠子合并起来的最大能量
在读入的时候现将珠子们先制一遍放到后面,断环成链
转移就枚举最后一步聚合的位置即可
状态转移方程:
f[ i ][ j ] = max( f[ i ][ j ] , f[ i ][ k ] + f[ k+1 ][ j ] + head[ i ] * tail[ k ] * tail[ j ] )
最优答案可能是之前就找到的,也可能是对于不同的断点k转移来的,左右取最优,然后合并左右
初始化 f [ i ] [ j ] = 0
ans也要二倍区间长取最优
时间复杂度 O(8n3)
代码
#include<bits/stdc++.h> using namespace std; int n,head[205],tail[205]; int f[205][205],ans=0; //初始化默认为0了 inline int read() { int ans=0; char last=' ',ch=getchar(); while(ch<'0'||ch>'9') last=ch,ch=getchar(); while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar(); if(last=='-') ans=-ans; return ans; } int main() { n=read(); for(int i=1;i<=n;i++) //环变链 { head[i]=read(); head[i+n]=head[i]; } for(int i=1;i<2*n;i++) //串起来 { tail[i]=head[i+1]; } tail[2*n]=head[1]; for(int l=2;l<=n;l++) //区间长 for(int i=1;i<=2*n-l+1;i++) //起点 { int j=i+l-1; //终点 for(int k=i;k<j;k++) //断点 f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+head[i]*tail[k]*tail[j]); } //二倍区间求最值 for(int i=1;i<=n;i++) ans=max(ans,f[i][i+n-1]); printf("%d ",ans); return 0; }