四边形不等式求解合并石子(菜鸡做法)

这里暂时先只提供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\n";
				}
				
			}cout<<'\n';
			
		}
	}
	
	ll ans=99999999;
	for(int i=1;i<=n;i++){
		ans=min(ans,f[i][i+n-1]);
	}
	
	cout<<ans<<'\n';
	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\n";
				}
				
			}cout<<'\n';
			
		}
	}
	
	ll ans=99999999;
	for(int i=1;i<=n;i++){
		ans=min(ans,f[i][i+n-1]);
	}
	
	cout<<ans<<'\n';
	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\n";
				}
				
			}cout<<'\n';
			
		}
	}*/
	
	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<<'\n';
	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\n";
				}
				
			}cout<<'\n';
			
		}
	}*/
	
	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<<'\n';
	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\n";
				}
				
			}cout<<'\n';
			
		}
	}*/
	
	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<<'\n';
	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\n";
				}
				
			}cout<<'\n';
			
		}
	}*/
	
	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<<'\n';
	return 0;
}

结果正确!!

综上:四边形不等式很简单,多试几次就好啦~~()

posted @ 2021-03-16 17:30  yxr~  阅读(50)  评论(0编辑  收藏  举报