分治算法总结

二分算法的总结

模板

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

最小值:

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( );
}

猜你喜欢

转载自www.cnblogs.com/the-Blog-of-Mikasa/p/12482652.html