刺客信条

题解:

类似于奶酪那道题。可以发现,教徒的控制区域是一个圆形,且要在每个圆的半径相等的情况下,使半径尽可能变大。半径越大,艾吉奥能通过的可能性越低,于是我们可以二分半径。

先预处理出两点之间的距离,尽量不要用sqrt或者pow。然后对于一个给定的半径,我们把相交的两个圆相连,然后,把与边界相交的圆与边界相连。如果我们能够从底边一个圆走到顶边,从左边走到右边,从左边走到下边,从右边走到上边,这几种情况都是不能从左下走到右上的。

我考试的时候是用图来连边,然后DFS判断联通,然后就莫名爆掉。最后是用并查集改对,当然DFS是要比并查集快一些,但并查集比较好些,两者各有优劣。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<climits>
#include<cmath>
#define MAXA 2005
using namespace std;
typedef long long LL;
bool Vis[MAXA];
int Ast[MAXA];
struct Rx {
	int a,b;
}Red[MAXA];

LL Dis(LL x1,LL y1,LL x2,LL y2) {
	return ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int x,y,n,s,e;
double Left,Right,Ans,Mid;
LL Dist[MAXA][MAXA];
int FindAst(int x) {
	if(x == Ast[x])
	   return Ast[x];
	Ast[x] = FindAst(Ast[x]);
	return Ast[x];
}
bool Check(double R) {
	for(int i=0;i<=n+1;i++)
	    Ast[i] = i;
	for(int i=1;i<=n;i++)
	    for(int j=i+1;j<=n && i!=j;j++)
	        if(Dist[i][j] < 4 * R * R) {
	        	int xAst = FindAst(i);
	        	int yAst = FindAst(j);
	        	Ast[yAst] = xAst;
			}
	for(int i=1;i<=n;i++) {
		int xAst = FindAst(s);
		int yAst = FindAst(e);
		int zAst = FindAst(i);
		if(Red[i].b < R || Red[i].a + R > (double)x)
		   Ast[xAst] = zAst;
		if(Red[i].a < R || Red[i].b + R > (double)y)
		   Ast[yAst] = zAst;
	}
	if(FindAst(s) == FindAst(e))
	   return false;
	else return true;
} 
int main() {
//	freopen("AC.in","r",stdin);
//	freopen("AC.out","w",stdout);
	scanf("%d %d %d",&x,&y,&n);
	for(int i=1;i<=n;i++)
	    scanf("%d %d",&Red[i].a,&Red[i].b);
	for(int i=1;i<=n;i++)
	    for(int j=i+1;j<=n;j++)
	        Dist[i][j] = Dist[j][i] = Dis((LL)Red[i].a,(LL)Red[i].b,(LL)Red[j].a,(LL)Red[j].b);
	Right = (double)x * (double)x + (double)y * (double)y;
	s = 0;
	e = n + 1;
	while(Left + 0.001 <= Right) {
		Mid = (Left + Right) / 2;
		if(Check(Mid)) {
			Ans = Mid;
			Left = Mid;
		}
		else Right = Mid;
	}
	printf("%.2lf",Ans);
}
/*
10 10 4
1 2
7 1
5 5
9 5
*/

猜你喜欢

转载自blog.csdn.net/qq_41513352/article/details/83115706