一道经典的题:https://www.luogu.org/problemnew/show/P1090
这道题虽然比普通的要多考虑一点,因为有环形,但我们仍然可以通过非环形的例子来做一下,再来做这道题。
分析:这道题如果用贪心的思路当然也可以,只需要每次都选择最小的两个数相加就可以了,这里就不附上代码了QAQ
非环形代码:这里需要做一个预处理,也就是计算一个前缀和,然后DP一下,当前如果是合并前两个还是后两个,代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2000+10;
int a[maxn],f[maxn][maxn],sum[maxn];
int main(){
int i,j,k,n,m;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=1000000;
for(int i=1;i<=n;i++){
cin>>a[i];
f[i][i]=0;
sum[i]=sum[i-1]+a[i];
}
for(int len=1;len<n;len++)
for(int i=1;i<n;i++){
int j=i+len;
if(j>n)
j=n;
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
}
cout<<f[1][n];
return 0;
}
做完了非环形代码,现在我们就能来做一下环形的代码了!!!
环形代码:如果是首尾相连,我们就可以在后面接上一段,保证转移方程可以继续正常运行,这样我们的程序也需要做一些改动:
#include <bits/stdc++.h>
using namespace std;
const int maxn=200+10;
int a[maxn],f[maxn][maxn],sum[maxn];
int main(){
int i,j,k,n,m;
cin>>n;
for(int i=1;i<=n*2;i++)
for(int j=1;j<=n*2;j++)
f[i][j]=1000000;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i+n]=a[i];
}
for(int i=1;i<=2*n;i++){
f[i][i]=0;
sum[i]=sum[i-1]+a[i];
}
for(int len=1;len<n;len++)
for(int i=1;i<2*n;i++){
int j=i+len;
if(j>2*n)
j=2*n;
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
}
int ans=100000;
for(int i=1;i<=n;i++)
ans=min(ans,f[i][i+n-1]);
cout<<ans;
return 0;
}
做完这道题,我们就可以挑战BOSS了!!!
https://www.luogu.org/problemnew/show/P1880
这一道题显然在环形上增加了最大值,以前求得是最小值,所以这样代码就可以构造出来了:
#include <bits/stdc++.h>
using namespace std;
const int maxn=200+10;
int a[maxn],f[maxn][maxn],sum[maxn],f1[maxn][maxn];
int main(){
int i,j,k,n,m;
cin>>n;
for(int i=1;i<=n*2;i++)
for(int j=1;j<=n*2;j++){
f[i][j]=1000000;
f1[i][j]=-1000000;
}
for(int i=1;i<=n;i++){
cin>>a[i];
a[i+n]=a[i];
}
for(int i=1;i<=2*n;i++){
f[i][i]=0;
f1[i][i]=0;
sum[i]=sum[i-1]+a[i];
}
for(int len=1;len<n;len++)
for(int i=1;i<2*n;i++){
int j=i+len;
if(j>2*n)
j=2*n;
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
}
for(int len=1;len<n;len++)
for(int i=1;i<2*n;i++){
int j=i+len;
if(j>2*n)
j=2*n;
for(int k=i;k<j;k++)
f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+sum[j]-sum[i-1]);
}
int ans=100000;
for(int i=1;i<=n;i++)
ans=min(ans,f[i][i+n-1]);
cout<<ans;
int ans1=-100000;
for(int i=1;i<=n;i++)
ans1=max(ans1,f1[i][i+n-1]);
cout<<endl<<ans1;
return 0;
}