一本通题解——1433 愤怒的牛

题目链接

一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid=1433

自己OJ:http://47.110.135.197/problem.php?id=4458

题目

题目描述

农夫 John 建造了一座很长的畜栏,它包括 N (2 ≤ N ≤ 100,000)个隔间,这些小隔间依次编号为x1, ..., xn (0 ≤ xi ≤ 1,000,000,000). 但是,John的 C (2 ≤ C ≤ N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。为了不让牛互相伤害。John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢?
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?

输入

第一行:空格分隔的两个整数 N 和 C ;
第二行---第N+1行: i + 1 行指出了 xi 的位置。
Line 1: Two space-separated integers: N and C
Lines 2..N+1: Line i+1 contains an integer stall location, xi

输出

一个整数,最大的最小值。
Line 1: One integer: the largest minimum distance

样例输入

5 3
1 2 8 4 9

样例输出

3

提示

把牛放在 1,4,8 这样最小距离是 3 。

题目分析

本题原题来自USACO 2005 Feb. Gold。一个二分查找的模板题。

题目分析

从题目可以知道。题目提供了现在有的牛栏编号 Xi 和牛的数量 C,由于牛比较好斗,如果两个牛放在同一个牛栏里,牛就会互相伤害。要求我们将牛放好(不会互相伤害),而且两头牛之间的最小距离最大。

这样我们可分析出如下内容:

1、要求两头牛之间的最小距离最大,而且题目没有告诉我们牛栏的编号 Xi 是有序的,所以肯定要先排序。

2、排序后,我们开始尝试放置 C 头牛,放置好了,求出最小距离,然后求最大值。8*7/2

这样问题就变成如何放置牛,并求出牛之间的最小距离,将所有方案进行比较即可。如何求呢?我们使用样例数据来模拟,排序好的牛栏 Xi 如下:

1 2 4 8 9

我们一共有 C 头牛,也就是 3 头牛。根据组合数学,我们知道一共有 \small \binom{3}{5} = \binom{2}{5} = \frac{5*4}{2}=10  种方法,我们用穷举方法,将所有的放置方法写出来,如下:

1、第 1 种方案,也就是将 3 头牛,分别放置在 1、2、4 这三个牛栏。那么牛的最小距离是 2 - 1 = 1 。

2、第 2 种方案,也就是将 3 头牛,分别放置在 1、2、8 这三个牛栏。那么牛的最小距离是 2 - 1 = 1 。

3、第 3 种方案,也就是将 3 头牛,分别放置在 1、2、9 这三个牛栏。那么牛的最小距离是 2 - 1 = 1 。

4、第 4 种方案,也就是将 3 头牛,分别放置在 1、4、8 这三个牛栏。那么牛的最小距离是 4 - 1 = 3 。

5、第 5 种方案,也就是将 3 头牛,分别放置在 1、4、9 这三个牛栏。那么牛的最小距离是 4 - 1 = 3 。

6、第 6 种方案,也就是将 3 头牛,分别放置在 1、8、9 这三个牛栏。那么牛的最小距离是 9 - 8 = 1 。

7、第 7 种方案,也就是将 3 头牛,分别放置在 2、4、8 这三个牛栏。那么牛的最小距离是 4 - 2 = 2 。

8、第 8 种方案,也就是将 3 头牛,分别放置在 2、4、9 这三个牛栏。那么牛的最小距离是 4 - 2 = 2 。

9、第 9 种方案,也就是将 3 头牛,分别放置在 2、8、9 这三个牛栏。那么牛的最小距离是 9 - 8 = 1 。

10、第 10 种方案,也就是将 3 头牛,分别放置在 4、8、9 这三个牛栏。那么牛的最小距离是 9 - 8 = 1 。

可以知道,两头牛之间最小距离的最大值为 3 。

算法思路

暴力

如同上面的数据分析,就是列出所有组合,就是一个 C (牛的数量)层循环。从题目的数据范围可以知道,\small C=N=100,000。那么计算的次数就是 \small 100000^{C} ,肯定是一个 TLE (超时)的结局。

二分

这样我们可以知道,就是一个标准的二分查找。查找的左边界(left)为 0 (两头牛放在一起),右边界(right)为 8 (9-1),假设中间值(mid)作为两头牛最小间隔的最大值,按照这个方案去分配牛,如果满足条件(就是这个方案可以放 C 头牛),我们缩小查找距离。直到查找结束,这个时候,右边界(right)就是所求的最下距离的最大值。

这样的我们知道算法的时间复杂度为 \small O(logN) 。从题目的数据范围可以知道,\small N=100,000,那么最是 \small log_2(100000)=\frac{log100000}{log2}=16.6,也就是最多 17 次就可以完成。

数学要求

从上面分析,我们可以知道,要求了解组合数学。

坑点

模板题,没有什么坑。即使是二分查找的中间值(mid)计算这个坑,由于  \small 0\leqslant X_{i} \leqslant 100,000,这个坑点也不会出现。

AC参考代码

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1e5;
int data[MAXN] = {};

int main(){
    int n, c;
    cin >> n >> c;
    int i;
    for (i=0; i<n; i++) {
        cin >> data[i];
    }

    //排序
    sort(data, data+n);

    //二分
    int left = 0;
    int right = data[n-1]-data[0];
    int mid;
    while (left<=right) {
        mid = left+(right-left)/2;

        //间隔mid的距离放置牛,进行合法性检查
        int cows = 1;//可以放几头牛
        int prev = data[0];//上一个牛所在的栏
        for (i=1; i<n; i++) {
            if (data[i]-prev>=mid) {
                //符合要求,放一头牛
                cows++;
                prev = data[i];

                //牛数量够了,降低计算量
                if (cows>=c) {
                    break;
                }
            }
        }

        if (cows >= c) {
            left = mid+1;
        } else {
            right = mid-1;
        }
    }

    cout << right << endl;

    return 0;
}

 

  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值