hw2021笔试第三场第一题
一开始死活通不过,一直为0,后来加了一句代码,过了80%,要哭了……
目录
题目描述
有一条水平线,水平线上有一些工位和消毒器械,位置均固定。消毒器械的工作范围是一个圆形,且所有的消毒器械工作半径均相同。要求覆盖所有的工位,试求,最小的工作半径为多少?
输入:第一行输入一个数组,代表工位位置;第二行输入一个数组,代表消毒器械的位置。
输出:最小工作半径大小
示例:
输入:
1 3 5
2
输出:
3
即,工作半径为3,消毒器械位置位于2,这样就可以覆盖所有工位1、3、5了。
思路
首先,工位和消毒器械都在同一条水平线上,还知道两者的位置,画个数轴就明确了。
用暴力的话,两层for循环,依次判断每个工位是否可以在某个消毒器械的范围内即可,但是很容易就超时了。换个思路,如果设置半径r为最远处的工位(5),是一定满足要求的。既然5可以,4是否可以,……,直到r为2时不满足条件,因此得到最小的工作半径为3。所以就变成了寻找半径可选值的左边界值,也就是最小的最大值,这样就可以用二分寻找了(可以看这个二分法代码分析-寻找左边界),即如果mid值符合要求,就继续向左找。二分部分代码如下:
void binarySearch(const vector<int>& work, const vector<int>& ster)
{
int small = 1, mid, big = maxWorkStation;
while (small <= big) {
mid = small + (big - small) / 2;
if (judge(work, ster, mid)) {
big = mid - 1;
} else {
small = mid + 1;
}
}
cout << small << endl; // big + 1也可
}
现在的关键就是如何判断半径r是满足要求的。我是在读入消毒器械位置后,计算了每个消毒器械工作范围的区间,即只记录区间两端的数值。如果两个消毒器械有重叠的工作范围,则将其合并为一个大区间,例如(1,3),(2,4)可合并为(1,4)。最后依次判断每个工位是否在这一系列区间内。(ps:如果要合并重叠区间的话,记得给第二行的输入数据排个序,就是因为这个一直0%)。判断部分代码如下:
bool judge(const vector<int>& work, const vector<int>& ster, int r)
{
vector<vector<int>> arr; // 存储区间端点值
vector<int> tmp;
tmp.push_back(ster[0] - r > 0 ? (ster[0]