Aggressive Cows(二分法查找最小值最大)

本文解决了一个经典的算法问题:如何在给定的牛棚布局中放置一定数量的牛,使得任意两头牛之间的最小距离尽可能大。通过二分查找的方法找到了最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

VOJ Aggressive cows

描述

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000). His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

Line 1: Two space-separated integers: N and C 

Lines 2..N+1: Line i+1 contains an integer stall location, xi

Output

Line 1: One integer: the largest minimum distance

Sample Input

5 3
1
2
8
4
9

Sample Output

3

题意

有N个房间,距离不定,往这N个房间中放C头牛,问怎么放可以使牛与牛之间的最小距离最大(前提是C头牛都放进去了)。

思路

二分查找解最小值最大问题。

查找一个mid对应为牛与牛之间距离最小值,设置二分下界为0,上届为所有房间中最大距离。

先对所有房间排序,然后从第一个房间遍历所有房间,每次查询一个房间,判断它能否塞一头牛(条件为该牛与上一头牛之间距离大于等于mid),若不能,继续查找下一个房间;若能,记下放牛个数,并刷新距离计数器为下一头牛与该牛的距离。直至遍历结束。判断放了几头牛,若个没放满,说明假设的mid太大了,需要mid=right-1;若正好放了C头牛或多放了,mid都可能还可以增大,因此先记录mid,再让mid=left-1。一路搜索,直到left>right。

注意

left+1前需要先记录mid,以免丢失正确答案。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int s[100005];
int INF=0x3ffff;
int n,c;
int minLen(int nowLen)
{
    int sum=0,nowPoi=s[1];//初始化
    for(int i=2;i<=n;)//第i个仓库
    {
        while(s[i]<nowLen+nowPoi)//while不能安排到第i个仓库
            i++;//跳到下一个仓库
        sum++;//计安排了几只羊的记数器+1
        //cout<<"sum-"<<sum<<endl;
        nowPoi=s[i];
    }
    return sum;
}
int main()
{
    fill(s+1,s+1+n,INF);
    scanf("%d %d",&n,&c);
    for(int i=1;i<=n;i++)
        scanf("%d",&s[i]);
    sort(s+1,s+1+n);
    int r=s[n]-s[1],l=0,ans=0;
    while(l <= r)
    {
        int mid=(l+r)/2;
        int num=minLen(mid);
        if(num>=c)
        {
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值