分治算法总结

二分算法的总结

模板

说到算法肯定要说到模板对吧:

最小值:

int l=1,r=n,mid;
while(r>l){
    mid=l+r>>1;
    if(check(mid))r=mid;
    else l=mid+1;
}
return r;

最大值:

int l=1,r=n,mid;
while(r>l){
    mid=l+r>>1
    if(check(mid))l=mid;
    else r=mid-1;
}
return l;

原理解析:

核心代码:

if(check(mid))r=mid;      //1
else l=mid+1;             //2

or

if(check(mid))l=mid;
else r=mid-1;

结合此图感性理解:

为什么会正确的呢?

这也是二分算法的难点 虽然很简单

mid合法时,他会被l或者r记录下来

在此对l-mid或者mid-r进行同样的操作,一直到区间不合法为止

模板清楚了,来练几道题

1.模板题

很简单的一道题

第一步:先找到k的范围

第二步:其次通过坐标-1+1找出连续的数起始位置和终止位置

code:
#include<bits/stdc++.h>
using namespace std;
int a[10000],n;
inline void find(int k){
	int l=1,r=n,mid;
	while(r>l){
		mid=l+r>>1;
		if(a[mid]<k)l=mid+1;
		else r=mid;
	}
	if(a[r]!=k){
		puts("-1 -1");
		return;
	}
	while(a[--r]==k);
	cout<<r<<" ";
	while(a[++r]==k);
	cout<<r-2<<endl;
}
int main( ){
	std::ios::sync_with_stdio(false);
	int m;
	cin>>n>>m;
	int l=1,r=n,k,i,j;
	for(i=1;i<=n;i++)cin>>a[i];
	for(i=1;i<=m;i++){
		cin>>k;
		find(k);
	}
}

2.二分答案

也挺简单的,二分答案+差分维护在二分的答案下每天需要的教室数量

code:
#include<bits/stdc++.h>
using namespace std;
int n,cf[1000100],l[1000100],r[1000100],d[1000100],most[1000100];
inline bool check(int k){
	memset(cf,0,sizeof(cf));
	int i,j;
	for(i=1;i<=k;i++){
		cf[l[i]]+=d[i];
		cf[r[i]+1]-=d[i];
	}
	for(i=1;i<=n;i++){
		cf[i]+=cf[i-1];
		if(cf[i]>most[i])return 0;
	}
	return 1;
}
int main( ){
	int m,ll,rr,mid,i;
	scanf("%d%d",&n,&m);
	ll=1;rr=m;
	for(i=1;i<=n;i++)scanf("%d",&most[i]);
	for(i=1;i<=m;i++)scanf("%d%d%d",&d[i],&l[i],&r[i]);
	if(check(m)){
		puts("0");
		return 0;
	}
	while(rr>ll){
		mid=(ll+rr)/2;
		if(check(mid))ll=mid+1;
		else rr=mid;
	}
	puts("-1");
	printf("%d",ll);
}

分割线


三分

由二分推广来的,主要解决单峰问题的

模板

code:求凸函数极限
double l=0,r=10000;
while(r-l>=0.01){//视精度而变化
    double m1=l+(r-l)/3,m2=r-(r-l)/3;
    if(f(m1)<f(m2))l=m1;
    else r=m2;
}
return f(r);

为什么要将小的那一个赋值为新的区间端点呢?

这也是理解三分的重点

明显的,我们要首先满足区间内要包含顶点

我们取的端点里,可能会有1个端点(最多1个)越过了顶峰

但是值最小的一定不会越过

模板题

1.模板题

典型的三分,前面已经讲了

code:
#include<bits/stdc++.h>
using namespace std;
int n,a[10011],b[10011],c[10011];
inline double courage(double x,int i){return x*x*a[i]+x*b[i]+c[i];}
inline double check(double x){
	double ans=courage(x,1);
	int i,j,k;
	for(i=2;i<=n;i++)
	ans=max(ans,courage(x,i));
	return ans;
}
inline void work( ){
	cin>>n;
	int i,j,k;
	for(i=1;i<=n;i++)cin>>a[i]>>b[i]>>c[i];
	double l=0,r=1000,emp=1e-11,mid1,mid2;
	while(r-l>emp){
		mid1=l+(r-l)/3.0;
		mid2=r-(r-l)/3.0;
		if(check(mid1)>check(mid2))l=mid1;
		else r=mid2;
	}
	printf("%.4lf\n",check(l));
}
int main( ){
	int t;
	std::ios::sync_with_stdio(false);
	cin>>t;
	while(t--)work( );
}
posted @ 2020-03-12 20:54  Mikasa_Ackerman  阅读(230)  评论(0编辑  收藏  举报