愤怒的牛/好斗的奶牛[二分答案]

题目来源

USACO 2005 Feb. Gold

题面

题目描述

农夫约翰建造了一座有 $n$ 间牛舍的小屋,牛舍排在一条直线上,第 $i$ 间牛舍在 $x_i$​ 的位置,但是约翰的 $m$ 头牛对小屋很不满意,因此经常互相攻击。约翰为了防止牛之间互相伤害,因此决定把每头牛都放在离其它牛尽可能远的牛舍。也就是要最大化最近的两头牛之间的距离。

牛们并不喜欢这种布局,而且几头牛放在一个隔间里,它们就要发生争斗。为了不让牛互相伤害。John 决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是多少呢?

输入格式

第一行用空格分隔的两个整数 $n$ 和 $m$ 。
第二行为 $n$ 个用空格隔开的整数,表示位置 $x_i$ 。

输出格式

输出仅一个整数,表示最大的最小距离值。

样例

输入

5 3
1 2 8 4 9

输出

3

数据范围

$2 \le n \le 10^5$
$0 \le x_i \le 10^9$
$2 \le m \le n$

思路

暴力枚举

从 $1$ 到 $n$ 枚举最小间隔,将牛依次放入符合这个距离的隔间,若发现满足条件就是最小答案,则直接输出 $i$ 。时间复杂度 $O(nm)$ ,超时。

二分答案

二分

给定一个区间,考察最中间的一个元素是否符合条件,再根据结果向左或向右继续考察,直到选出最佳元素。

二分代码

int l=0,r=n;
while(l+1<r)
{
	int mid=(l+r)/2;
	if(check(mid)) l=mid;
	else r=mid;
}
return l;

正解

本题适宜二分答案,即二分最小距离值的所有可能性,然后贪心将牛放入隔间。

标程

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
int n,m,a[N];

bool check(int mid)//贪心将奶牛放入隔间
{
	int now=a[1],cnt=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]-now>=mid) cnt++,now=a[i];
       	if(cnt>=m) return 1;
    }
    return 0;
}

int solve()//二分答案
{
    int l=0,r=a[n];
    while(l+1<r)
    {
        int mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    return l;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    	scanf("%d",a+i);
    sort(a+1,a+n+1);
    printf("%d\n",solve());
    return 0;
}
posted @ 2024-12-15 07:32  lfggy  阅读(12)  评论(0编辑  收藏  举报