神奇的二分



今天看挑战程序设计看到了二分的知识,觉得那是相当的神奇啊啊啊啊,没有之一。。。

下面来总结下今天过了的4道二分的题目。

POJ 1064 Cable master

题意:大概意思就是说给你n根绳子,要在这n根绳子中剪K段,每段一样长,问最长每段为多少

思路:很简单的初级二分嘛,枚举下每段绳子的长度,然后用这个长度去看看每段绳子能剪几段,加起来够不够K,枚举是采用二分的,所以是logn级别,判断是n,所以复杂度是

n*logn

源码:

#include<cstdio>
#include<cmath>
int n,k;
double L[10005];
bool C(double d)
{
    int num=0;
    for(int i=0;i<n;i++)
    {
        num+=(int)(L[i]/d);
    }
    return num>=k;
}
void slove()
{
    //freopen("debug\\in.txt","r",stdin);
    double lb=0,ub=99999999;
    for(int i=0;i<100;i++)
    {
        double mid=(lb+ub)/2;
        if(C(mid))lb=mid;
        else ub=mid;
    }
    printf("%.2f\n",floor(ub*100)/100);
}
int main()
{
    //freopen("debug\\in.txt","r",stdin);
    while(scanf("%d%d",&n,&k)==2)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%lf",&L[i]);
        }
        slove();
    }
    return 0;
}

POJ 2456

题意:就讲的是有n个房子,要在这n个房子中放m头牛,使相邻两头牛间的距离最大

思路:这道题看似是贪心,但是如果仅仅是一个个去比较的话会比较麻烦,这里用到了二分,我们首先想到二分的次数越多,精度会越高,放到题目中,则是越接近答案

我们就可以枚举两头牛间的距离,如果刚好能放下m头牛,且最小的距离小于d的话,那么我们就向上届继续二分,这里直接贴板即可,这种题目叫做最大化最小值

下面是源码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,c;
long long x[100005];
bool C(long long d)
{
    int last=0;
    for(int i=1;i<c;i++)
    {
        int next=last+1;
        while(next<n&&x[next]-x[last]<d)
            next++;
        if(next==n)return false;
        last=next;
    }
    return true;
}
void Slove()
{
    sort(x,x+n);
    long long lb=0;
    long long ub=1000000009;
    while(ub-lb>1)
    {
        long long mid=(ub+lb)/2;
        if(C(mid))lb=mid;
        else ub=mid;
    }
    printf("%lld\n",lb);
}
int main()
{
    while(scanf("%d%d",&n,&c)==2)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%lld",&x[i]);
        }
        Slove();
    }
    return 0;
}

POJ3258

题意:这道题讲跟上面那道题是一样的,就是n+2个点,删去m个点,使得相邻两石头最短距离最大,这道题联系上面那道题可以转化为n+2中放N+2-m头牛的问题,那么又回到上面那道题的解法了

下面是源码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long x[50010];
long long l,n,m;
bool C(long long d)
{
    int last=0;
    for(int i=1;i<n+2-m;i++)
    {
        int next=last+1;
        while(next<n+2&&x[next]-x[last]<d)
            next++;
        if(next==n+2)return false;
        last=next;
    }
    return true;
}
void Slove()
{
    sort(x,x+n+2);
    long long lb=0,ub=1000000009;
    while(ub-lb>1)
    {
        long long mid=(lb+ub)/2;
        if(C(mid))lb=mid;
        else ub=mid;
    }
    printf("%lld\n",lb);
}
int main()
{
    //freopen("debug\\in.txt","r",stdin);
    while(scanf("%lld%lld%lld",&l,&n,&m)==3)
    {
        for(int i=1;i<=n;i++)
            scanf("%lld",&x[i]);
        x[0]=0;
        x[n+1]=l;
        Slove();
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值