思路:
很简单的区间dp,注意最外层循环设置成(当前合并区间长度)和(当前合并次数)之间的差异
代码:(当前合并的区间长度)
```cpp #includeusing namespace std;
struct node{
ll l,r;
}a[maxn];
ll f[maxn][maxn],n;
//2 3 5 10 2 3 5 10
int main()
{
memset(f,0,sizeof(f));
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].l ;
a[i-1].r =a[i].l ;
a[i+n].l =a[i].l ;
a[i+n-1].r =a[i].l ;
}
a[2*n].r =a[1].l ;
// for(int i=1;i<=2n;i++) cout<<a[i].l <<" "<<a[i].r <<'
';
for(int l=2;l<=n;l++)//枚举区间长度
{
for(int i=1;i+l-1<=2n;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]+a[i].l*a[k].r *a[j].r);
// cout<<i<<" "<<j<<" "<<k<<" "<<f[i][j]<<" "<<f[i][k]<<" "<<f[k+1][j]<<" "<<a[k].l <<" "<<a[k].r <<" "<<a[k+1].r <<'
';
}
}
}
ll ans=0;
/*
for(int i=1;i<=2*n;i++)
{
for(int j=1;j<=2*n;j++)
{
cout<<f[i][j]<<" ";
}
cout<<'
';
}*/
for(int i=1;i<=n;i++)
{
ans=max(ans,f[i][i+n-1]);
}
cout<<ans<<'
';
return 0;
}
(当前合并次数):
```cpp
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int f[210][210];
struct node
{
int x,y; //头标记和尾标记
}a[210];
int main()
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i-1].y=a[i].x; //前一个珠子的尾标记等于后一个珠子的头标记
}
a[n].y=a[1].x; //注意是环!收尾相连
for (int i=1;i<n;i++)
a[i+n]=a[i]; //复制一段在后边,那么从i~i+n就是看成是一个从i开始的一条线了,省了一条循环
memset(f,0,sizeof(f)); //赋0
//f[i][j]:合并第i~j个珠子时的最优情况
for (int k=1;k<=n;k++) //枚举长度(与合并石子的x相似)
{
for (int i=1;i<2*n-k;i++) //从第i个石子开始断,,那么从i~i+n就是一条线
{
for (int j=i;j<i+k;j++) //在i~i+k中选一个点j分成i~j和j+1~i+k两段(与合并石子的k相同)
{
f[i][i+k]=max(f[i][i+k],f[i][j]+f[j+1][i+k]+a[i].x*a[j].y*a[i+k].y); //计算能量
}
}
}
int ans=0;
for (int i=1;i<=n;i++)
{
ans=max(f[i][i+n-1],ans);
//扫一遍,看看从哪里断得到的值最大
}
for(int i=1;i<=2*n;i++)
{
for(int j=1;j<=2*n;j++) cout<<f[i][j]<<" ";
cout<<'
';
}
printf("%d",ans);
return 0;
}