tywzoj.top_第318题_路由器安置_题解

题目描述

一条街道安装WIFI,需要放置M个路由器。整条街道上一共有N户居民,分布在一条直线上,每一户居民必须被至少一台路由器覆盖到。现在的问题是所有路由器的覆盖半径是一样的,我们希望用覆盖半径尽可能小的路由器来完成任务,因为这样可以节省成本。

输入格式

输入文件第一行包含两个整数M和N,以下N行每行一个整数Hi表示该户居民在街道上相对于某个点的坐标。

输出格式

输出文件仅包含一个数,表示最小的覆盖半径,保留一位小数。

样例

input

2 3
1
3
10 

output

1.0 

数据范围与提示

时间限制:

1s

空间限制:

256MB

注释

对于60%的数据,有1 ≤ N, M ≤ 100,-1000 ≤ Hi ≤ 1000; 对于100%的数据,有1 ≤ N, M ≤ 100000,-10000000 ≤ Hi ≤ 10000000。

分类标签

二分答案   分治 

正片开始(前面算凑字数):

这是一道二分答案题,至于二分答案是啥(或不知道二分答案咋写)……(看这篇文章:二分答案),要查找一个正确答案,然而结果需要保留一位小数,所以查找答案时需要从0.1开始找。

首先输入:

    cin >> m >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }

当然二分答案之前需要先排序这是常识其实是因为题目没有说数据是有序地

    sort(a + 1, a + n + 1);

重点:

在我们二分时,每次二分出来的答案都学要判断是否符合题意

首先外层循环循环m也就是路由器的个数,为了让路由器覆盖的范围最佳化(其实是贪心思路),让最左边收到路由器覆盖范围的边缘,再搞一个路由器覆盖的边缘的最右边,也就是:

bool judge(double x) {
    int f = 0;
    for (int i = 1; i <= m; i++) {
        double o = a[f + 1] + x * 2;

    }
}

内层循环从f循环到n,但凡有个房屋的坐标小于上面的o,f++使已经接受的房屋不需要路由器的照顾,否则结束循环,要不然会超时

bool judge(double x) {
    int f = 0;
    for (int i = 1; i <= m; i++) {
        double o = a[f + 1] + x * 2;
        for (int j = f + 1; j <= n; j++) {
            if (a[j] <= o)
                f++;
            else
                break;
        }
    }
}

最后那个返回值的问题,如果f==n时,或者f==n并且该答案使得不需要那么多路由器就返回1,否则返回0。

bool judge(double x) {
    int f = 0;
    for (int i = 1; i <= m; i++) {
        double o = a[f + 1] + x * 2;
        for (int j = f + 1; j <= n; j++) {
            if (a[j] <= o)
                f++;
            else
                break;
            if (f == n && i != m)
                return 1;
        }
    }
    if (f == n)
        return 1;
    else
        return 0;
}

以上是判断二分答案是否符合题意,以下二分

二分之前先排序

    sort(a + 1, a + n + 1);

二分时找边界

左边界自然是0-0.1,右边界可以是  在最左边的房屋最右边的房屋距离(同样也可以是20000000),所以找最大值最小值在输入里找:

    cin >> m >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        maxx = max(a[i], maxx);
        minn = min(a[i], minn);
    }
    sort(a + 1, a + n + 1);
    double l = 0.01, r = maxx - minn, mid;

或者:


    cin >> m >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    sort(a + 1, a + n + 1);
    double l = 0.01, r = 20000000, mid;

边界为r-l>0.001,所以二分:

    while (r - l > 0.001) {
        mid = (l + r) / 2;
        if (judge(mid)) {
            r = mid - 0.01;
        } else {
            l = mid;
        }
    }

输出保留一位小数:

    cout << fixed << setprecision(1) << l;

然后就没有了。。。

好得

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值