原题链接:https://www.luogu.org/problem/show?pid=1063
区间DP题,即把整个问题划分成若干个小区间求解。
这个题细节太多了。。。
最后犯了一个傻逼性错误,数组开小了,死活过不了最后两个点
现在洛谷关站维护中,所以这题我在codevs上跑的。
思路是用f[i][j]表示这条项链上的珠子从i号位合到j号位的最大价值。状态转移方程为f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+a[i]*a[k+1]*a[j+1])。
不过题意说到数据是一个环,这里有两种处理方式。
一种是绝大多数题解里用的化环为链的方法将它变成链状,还有的题解是计算时取模,把这个数据就当成环来看待。
我写的也是化环为链,即在记录a数组的时候把数组开二倍大,i+n处也存储i位置的值,这样就可以模拟出中间的接口。
首先有一个i枚举到2n,枚举的是区间大小,然后有一个l枚举的是左端点,其应该满足l+i-1<2*N,也就是不让右端点越界 。
然后设一个变量r为l+i-1,这个代表的是右端点,然后有一个k从l枚举到r,枚举的是所谓断点。断点实际上就是我们要试图合并的位置。
进行转移,然后枚举1到n处理ans为max(f[i][i+n-1]),最后输出ans就好。
参考代码:
1 #include <iostream> 2 #define maxn 300 3 using namespace std; 4 int f[maxn][maxn]; 5 int a[maxn]; 6 int n,ans; 7 8 int main(){ 9 cin >> n; 10 for (int i=1;i<=n;i++){ 11 cin >> a[i]; 12 a[i+n] = a[i]; 13 } 14 for (int i=2;i<=2*n;i++) 15 for (int l=1;l+i-1<=2*n;l++){ 16 int r=l+i-1; 17 for (int k=l;k<=r;k++) 18 f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]+a[l]*a[k+1]*a[r+1]); 19 } 20 21 for (int i=1;i<=n;i++) 22 ans = max(ans,f[i][i+n-1]); 23 cout << ans << endl; 24 return 0; 25 }