二分法

最近又碰到了二分法的题目,可惜题都没读懂(好像后来读懂了也没啥用),于是决定做几道二分的巩固一下。

一:

题目链接: HDU 1969 Pie

思路分析

利用二分法找能平均分到的最大体积,如果要按这个体积数分,而分得的人数少于总人数,说明这个体积数大了,就向小的体积数继续查找。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
const int inf=0x3f3f3f3f;
const double eps=1e-6;
const double pi=acos(-1.0);
int main()
{
   int T,N,F,i,a[10001],temp;
   double sum,l,r,mid;
   cin>>T;
   while(T--)
   {
       sum=0;
       cin>>N>>F;
       for(i=1;i<=N;i++)
       {
           cin>>a[i];
           sum+=a[i]*a[i]*pi;
       }
       l=0,r=sum/(F+1);
       while(r-l>eps)         //注意double类型的比较
       {
           temp=0;
           mid=(l+r)/2.0;
           for(i=1;i<=N;i++)
            temp+=(int)((a[i]*a[i]*pi)/mid);             //此体积数下,能够分给多少人,注意取整。
           if(temp<F+1)
             r=mid;
           else
             l=mid;
       }
       printf("%.4f\n",mid);
   }
}

二:

题目链接: Hdu 1551 Cable master

思路分析

和上面的题几乎相同,依旧是注意精度问题。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
const int inf=0x3f3f3f3f;
const double eps=1e-10;
int main()
{
    int N,K,i,time;
    double l,r,sum,a[10001],mid;
    while(cin>>N>>K && N)
    {
    for(i=1;i<=N;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    l=0,r=sum/K;
    while(r-l>eps)
    {
        time=0;
        mid=(l+r)/2;
        for(i=1;i<=N;i++)
          time+=(int)(a[i]/mid);
        if(time<K)
            r=mid;
        else
            l=mid;
    }
    printf("%.2lf\n",mid);
    }
}

题目链接: HDU 2199 Can you solve this equation?

思路分析

这个也没什么分析的了,就是套二分的模板了。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
const int inf=0x3f3f3f3f;
const double eps=1e-10;
int main()
{
    int T,n;
    double l,r,mid;
    cin>>T;
    while(T--)
    {
        cin>>n;
        l=0,r=100;
        if(n<6 || 8*pow(100,4) + 7*pow(100,3) + 2*pow(100,2) + 3*100 + 6 <n)
        printf("No solution!\n");
        else
        {
        while(r-l>eps)
        {
            mid=(l+r)/2;
            if(8*pow(mid,4) + 7*pow(mid,3) + 2*pow(mid,2) + 3*mid + 6 >n)
                r=mid;
            else if(8*pow(mid,4) + 7*pow(mid,3) + 2*pow(mid,2) + 3*mid + 6 <=n)
                l=mid;
        }
        printf("%.4f\n",mid);
        }
    }
}

四:

题目链接: HDU 3258 River Hopscotch

思路分析

最小值最大化,就用二分了,只不过判断的过程需要想一想,N-M+1代表删掉M个数之后剩余的区间数目,如果counter大于这个数目,说明此时正在判断的数字过小,否则则过大。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
int L,N,M,a[50005];
const int inf=0x3f3f3f3f;
int elect(int x)
{
    int p=0,i,counter=0;
    for(i=1;i<=N+1;i++)
    {
        if(a[i]-p>=x)
        {
            counter++;
            p=a[i];
        }
    }
    return counter<N-M+1;
}
int main()
{
    int l,r,i,mid;
    cin>>L>>N>>M;
    for(i=1;i<=N;i++)
        cin>>a[i];
    a[0]=0;
    a[N+1]=L;
    sort(a,a+N+2);
    l=1,r=L;
    while(l<=r)
    {
         mid=(l+r)/2;
        if(elect(mid))
         r=mid-1;
        else
         l=mid+1;
    }
    cout<<l-1<<endl;
}

以后继续补充,感觉二分有些细节又清楚了许多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值