这里暂时先只提供min的做法,求max的时候直接把值改成负数即可
dp:
f[i][j]=f[i][k]+f[k+1][j]+d[j]-d[i-1];
正常代码:
#include<bits/stdc++.h>
#define ll long long
#define maxn 402
using namespace std;
ll n,a[maxn];
ll f[maxn][maxn];
ll d[maxn];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
memset(f,0x3f,sizeof(f));
for(int i=1;i<=2*n;i++)
{
d[i]=d[i-1]+a[i];
f[i][i]=0;
}
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++){
// cout<<f[i][]
if(f[i][j]>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
cout<<k<<" ";
f[i][j]=f[i][k]+f[k+1][j]+d[j]-d[i-1];
// cout<<"jnvadl
";
}
}cout<<'
';
}
}
ll ans=99999999;
for(int i=1;i<=n;i++){
ans=min(ans,f[i][i+n-1]);
}
cout<<ans<<'
';
return 0;
}
如果想用四边形不等式来做,那么我们先判断这个式子是不是符合四边形不等式的条件,发现和模板长得好像差不多~~
我们接着枚举断点k,看一看是不是有单调性:
#include<bits/stdc++.h>
#define ll long long
#define maxn 402
using namespace std;
ll n,a[maxn];
ll f[maxn][maxn];
ll d[maxn];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
memset(f,0x3f,sizeof(f));
for(int i=1;i<=2*n;i++)
{
d[i]=d[i-1]+a[i];
f[i][i]=0;
}
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++){
// cout<<f[i][]
if(f[i][j]>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
cout<<k<<" ";
f[i][j]=f[i][k]+f[k+1][j]+d[j]-d[i-1];
// cout<<"jnvadl
";
}
}cout<<'
';
}
}
ll ans=99999999;
for(int i=1;i<=n;i++){
ans=min(ans,f[i][i+n-1]);
}
cout<<ans<<'
';
return 0;
}
结果:
4
4 5 9 4
1
2
3
4
5
6
7
1 2
2
3
4 5
5 6
6
1 2
2 3
3
4 5 6
5 6
43
发现的确是有单调性的,所以我们的dp也有很大可能具有单调性
两个都试一下:
第一个;
f[i+1][j]<=s[i][j]<=f[i][j-1]
i正序枚举:
#include<bits/stdc++.h>
#define ll long long
#define maxn 402
using namespace std;
ll n,a[maxn];
ll f[maxn][maxn];
ll d[maxn],s[maxn][maxn];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i],s[i][i]=i,s[i+n][i+n]=i+n;
memset(f,0x3f,sizeof(f));
for(int i=1;i<=2*n;i++)
{
d[i]=d[i-1]+a[i];
f[i][i]=0;
}
/*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++){
// cout<<f[i][]
if(f[i][j]>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
cout<<k<<" ";
f[i][j]=f[i][k]+f[k+1][j]+d[j]-d[i-1];
// cout<<"jnvadl
";
}
}cout<<'
';
}
}*/
for(int i=1;i<=2*n;i++)
for(int j=i+1;j<=2*n;j++){
ll tmp=0x3f3f3f3f3f,p;
for(int k=s[i+1][j];k<=s[i][j-1];k++){
if(tmp>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
tmp=f[i][k]+f[k+1][j]+d[j]-d[i-1];
p=k;
}
}
f[i][j]=tmp;
s[i][j]=p;//决策点
}
ll ans=99999999;
for(int i=1;i<=n;i++){
ans=min(ans,f[i][i+n-1]);
}
cout<<ans<<'
';
return 0;
}
结果错误~~
i倒序枚举;
#include<bits/stdc++.h>
#define ll long long
#define maxn 402
using namespace std;
ll n,a[maxn];
ll f[maxn][maxn];
ll d[maxn],s[maxn][maxn];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i],s[i][i]=i,s[i+n][i+n]=i+n;
memset(f,0x3f,sizeof(f));
for(int i=1;i<=2*n;i++)
{
d[i]=d[i-1]+a[i];
f[i][i]=0;
}
/*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++){
// cout<<f[i][]
if(f[i][j]>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
cout<<k<<" ";
f[i][j]=f[i][k]+f[k+1][j]+d[j]-d[i-1];
// cout<<"jnvadl
";
}
}cout<<'
';
}
}*/
for(int i=n*2;i>=1;i--)//倒叙
for(int j=i+1;j<=2*n;j++){
ll tmp=0x3f3f3f3f3f,p;
for(int k=s[i+1][j];k<=s[i][j-1];k++){
if(tmp>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
tmp=f[i][k]+f[k+1][j]+d[j]-d[i-1];
p=k;
}
}
f[i][j]=tmp;
s[i][j]=p;//决策点
}
ll ans=99999999;
for(int i=1;i<=n;i++){
ans=min(ans,f[i][i+n-1]);
}
cout<<ans<<'
';
return 0;
}
结果错误~~
试一试第二种:
s[i][j-1]<=s[i][j]<=s[i+1][j]
i正序:
#include<bits/stdc++.h>
#define ll long long
#define maxn 402
using namespace std;
ll n,a[maxn];
ll f[maxn][maxn];
ll d[maxn],s[maxn][maxn];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i],s[i][i]=i,s[i+n][i+n]=i+n;
memset(f,0x3f,sizeof(f));
for(int i=1;i<=2*n;i++)
{
d[i]=d[i-1]+a[i];
f[i][i]=0;
}
/*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++){
// cout<<f[i][]
if(f[i][j]>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
cout<<k<<" ";
f[i][j]=f[i][k]+f[k+1][j]+d[j]-d[i-1];
// cout<<"jnvadl
";
}
}cout<<'
';
}
}*/
for(int i=1;i<=2*n;i++)
for(int j=i+1;j<=2*n;j++){
ll tmp=0x3f3f3f3f3f,p;
for(int k=s[i][j-1];k<=s[i+1][j];k++){
if(tmp>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
tmp=f[i][k]+f[k+1][j]+d[j]-d[i-1];
p=k;
}
}
f[i][j]=tmp;
s[i][j]=p;//决策点
}
ll ans=99999999;
for(int i=1;i<=n;i++){
ans=min(ans,f[i][i+n-1]);
}
cout<<ans<<'
';
return 0;
}
结果错误
倒序:
#include<bits/stdc++.h>
#define ll long long
#define maxn 402
using namespace std;
ll n,a[maxn];
ll f[maxn][maxn];
ll d[maxn],s[maxn][maxn];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i],s[i][i]=i,s[i+n][i+n]=i+n;
memset(f,0x3f,sizeof(f));
for(int i=1;i<=2*n;i++)
{
d[i]=d[i-1]+a[i];
f[i][i]=0;
}
/*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++){
// cout<<f[i][]
if(f[i][j]>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
cout<<k<<" ";
f[i][j]=f[i][k]+f[k+1][j]+d[j]-d[i-1];
// cout<<"jnvadl
";
}
}cout<<'
';
}
}*/
for(int i=n*2;i>=1;i--)//倒叙
for(int j=i+1;j<=2*n;j++){
ll tmp=0x3f3f3f3f3f,p;
for(int k=s[i][j-1];k<=s[i+1][j];k++){
if(tmp>f[i][k]+f[k+1][j]+d[j]-d[i-1]){
tmp=f[i][k]+f[k+1][j]+d[j]-d[i-1];
p=k;
}
}
f[i][j]=tmp;
s[i][j]=p;//决策点
}
ll ans=99999999;
for(int i=1;i<=n;i++){
ans=min(ans,f[i][i+n-1]);
}
cout<<ans<<'
';
return 0;
}
结果正确!!
综上:四边形不等式很简单,多试几次就好啦~~(▽)