T428497 请不要抢走爱丽丝的工作! 题解
题目传送门
本题要求扫地机器人半径 \(r\) 的最大值,既然要求最大值,容易想到二分答案。
那问题就转换为给定半径 \(R\) , 判断 \(R\) 满不满足条件,也就是能不能找到一条绕过所有障碍的路径。让我们逆转一下思维,考虑哪些区域是机器人不能到达的。简单分析就能得到以下结论:
- 与边界的距离小于 \(R\) 的点是不能到达的,这些点形成了一个矩形区域
- 与某一个障碍物的距离小于 \(R\) 的点是不能到达的,这些点形成了一个圆形区域
把这些区域全都画出来,如果发现上边界和下边界被这些区域连到一起了,就说明不存在能绕过这些不可达区域的路径,反之则存在。
分析到这里显然是要用并查集来判断上边界和下边界是否连通了,如果某个障碍物与边界的距离小于 \(2\times{R}\) ,则将此障碍物与边界相连, 如果两个障碍物之间的距离小于 \(2\times{R}\),则将这两个障碍物相连。以下是AC代码:
#include <bits/stdc++.h>
#define MAXN 105
using namespace std;
int px[MAXN];
int py[MAXN];
double dis[MAXN][MAXN];
int pre[MAXN];int root(int x){return pre[x] = pre[x]==x?x:(root(pre[x]));
}void merge(int x,int y){x = root(x);y = root(y);if(x!=y) pre[x] = y;
}bool check(double m,int n){memset(pre,0,sizeof(pre));for(int i=0;i<MAXN;i++) pre[i] = i; // 101号设为上边界, 102号设为下边界for(int i=0;i<n;i++){if(100.0-py[i]<2*m) merge(101,i);if(py[i]+100.0<2*m) merge(102,i);}for(int i=0;i<n-1;i++){for(int j=i+1;j<n;j++){if(dis[i][j]<2*m) merge(i,j);}}if(root(101)==root(102)) return true;else return false;
}void solve(){int n;cin >> n;memset(px,0,sizeof(px));memset(py,0,sizeof(py));memset(dis,0,sizeof(dis));for(int i=0;i<n;i++){cin >> px[i] >> py[i];}for(int i=0;i<n-1;i++){for(int j=i+1;j<n;j++){dis[i][j] = dis[j][i] = sqrt(pow(px[i]-px[j],2)+pow(py[i]-py[j],2));}}double l = 0, r = 100, lm = 10000;while(l<=r){double m = (l+r)/2;if(abs(lm-m)<1e-6) break;lm = m;if(check(m,n)){r = m;}else{l = m;}}cout << lm;
}int main(){int t = 1;
// cin >> t;while(t--){solve();}
}