题目描述
一条街道安装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;
然后就没有了。。。
好得