T428497 请不要抢走爱丽丝的工作! 题解

T428497 请不要抢走爱丽丝的工作! 题解

请不要抢走爱丽丝的工作

题目传送门

本题要求扫地机器人半径 \(r\) 的最大值,既然要求最大值,容易想到二分答案
那问题就转换为给定半径 \(R\) , 判断 \(R\) 满不满足条件,也就是能不能找到一条绕过所有障碍的路径。让我们逆转一下思维,考虑哪些区域是机器人不能到达的。简单分析就能得到以下结论:

  1. 与边界的距离小于 \(R\) 的点是不能到达的,这些点形成了一个矩形区域
  2. 与某一个障碍物的距离小于 \(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();
	}
}
posted @ 2025-03-11 19:02  古明地恋想睡觉  阅读(59)  评论(0)    收藏  举报