2018年4月24日

        ## 总结

前几天刚刚又学了二分法,我们今天就来总结一下。
所谓二分法,在我的理解看来,就是知道了答案的区间,按照二分查找的思想,快速的在这个区间里找到答案。
当然这是我的理解,如有错误,还请指正。
下面不多说,我们上例题。

例题

将n根网线切成k段相同长度的网线,问可切成的最长长度是多少;

对于这个问题,我们用二分法求解。
用mid去假设最大长度,利用mid越大切出的根数越少这一单调性。
注意:if(num>=k) l=mid ; 这句话是找最大值的关键,当可以切出k根甚至更多时,此时通过l=mid让一个大一些的长度去试,通过这个过程找到最大值 。

int n,k;
double a[10005],sum;
int judge(double s)
{
    int cnt = 0;
    for(int i = 0; i<n; i++)
    {
        cnt+=(int)(a[i]/s);
    }
    if(cnt>=k) return 1;
    return 0;
}
int i;
    while(~scanf("%d%d",&n,&k),n+k)
    {
        sum = 0;
        for(i = 0; i<n; i++)
        {
            scanf("%lf",&a[i]);
            sum+=a[i];
        }
        sum = sum/k;
        double l = 0,r = sum;
        while(fabs(l-r)>exp)
 	 {
            double mid = (l+r)/2;
            if(judge(mid))
                l = mid;
            else
                r = mid;
         }
        printf("%.2f\n",l);
        }
        return 0;
        }

还有

有f+1个人分n块披萨,每个人要求分得的面积一样,且披萨只能被切开而不能重新组合,求每个人能分到的最大面积s。

这个和上个题的思路是差不多的,不过这个从长度换成了面积。

#define pi 3.14159265358979
#define MAX 10010
using namespace std;
long long size[MAX];
int c,n,f;
bool judge(long long x)
{
    long long m = 0;
    for(int i = 0;i < n;i++){
        m += size[i] / x;
    }
    return m >= f;
}
int main()
{
    long long high,mid,low,res;
    int a;
    cin>>c;
    while(c --){
        cin>>n>>f;
        f += 1;
        low = 0;
        high = 0;
        res = 0;
        a = 0;
        for(int i = 0;i < n;i++){
            cin>>a;
            size[i] = a*a*pi*1000000;
            high += size[i];
        }
while(low <= high){
            mid = (low + high)/2;
            if(judge(mid)){
                low = mid+1;
     res = mid;
            }
            else
                high = mid-1;
        }
        printf("%.4lf\n",(double)res/1000000);
    }
    return 0;
   }

还有一个。

有一条河,河的长度已知,河中间有一些石头,石头的数量知道,相邻两块石头之间的距离已知。现在可以移除一些石头,问移除m块石头后,相邻两块石头之间的距离的最小值最大是多少。

这个依然是用二分。

typedef long long LL;
const int N = 50010;
LL num[N];
int main(){
 //freopen("1.txt","r",stdin);
 LL len;
 int n,m;
 while(scanf("%lld%d%d",&len,&n,&m) != EOF){
    memset(num,0,sizeof(num));
    num[0] = 0;
    for(int i = 1; i <= n; ++i)
     scanf("%lld",&num[i]);
    num[n+1] = len;
    sort(num,num+n+2);
       lp=1,rp=len;
       //上面为准备阶段
       while(lp < rp){
       int cnt = 0;
    LL mmid = (lp + rp) / 2;//中点
    for(int i = 1,j = 0; i <= n + 1; i++ )
     if(num[i] - num[j] <= mmid)//当它小于中点值时,++
         cnt++;
                else
       j = i;
       if(cnt > m)//当它大于m时,就要把mmid赋值给rp
     rp = mmid;
    else
     lp = mmid + 1;
    }
       printf("%lld\n",lp);
 }
 return 0;
 }

说实话,上面的代码其实我也很迷,似懂非懂的,也解释不清。

感悟

上一次本来说要弄搜索的题目。
但是我真的不会呀。。。。
现在才做出来两个。
还是看着解析做的。。。
我没救了。。。
等以后吧。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值