Jzoj P5904 刺客信条___二分+并查集

206 篇文章 0 订阅
30 篇文章 0 订阅

题目大意:

给出一个 n ∗ m n*m nm的图,图上有 T T T个点 ( a i , b i ) (a_i,b_i) (aibi),左上角是 ( 0 , 0 ) (0,0) (0,0),右下角是 ( n , m ) (n,m) (n,m),设一条路径从 ( 0 , 0 ) (0,0) (0,0) ( n , m ) (n,m) (n,m),其中路径上所有点分别离 T T T个点中最近的点的距离是 x 1 , x 2 x_1,x_2 x1,x2,设其中最小值是 y i y_i yi,问所有从 ( 0 , 0 ) (0,0) (0,0) ( n , m ) (n,m) (n,m)的路径中可能出现的 y i y_i yi的最大值是多少。

分析:

二分一个答案 x x x
然后T个 点 点 分别以 x x x为半径,就成了图上有若干个圆,
若干个圆可以构成多个联通块,我们利用并查集求出联通块以后,
判断一下是否存在联通块能把起点到终点的路径给完全挡住即可

代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#define eps 1e-6
#define N 2005

using namespace std;

struct Text { bool A, B, C, D; }e[N]; 
struct Node { double x, y; }a[N];
int fa[N], T;
double n, m ;
 
int Find(int x)
{
    if (fa[x] == x) return x;
    fa[x] = Find(fa[x]);
	return fa[x];  	
}

bool Calc(double x)
{
	for (int i = 1; i <= T; i++) 
	     e[i].A = e[i].B = e[i].C = e[i].D = 0, fa[i] = i;
	for (int i = 1; i <= T; i++)
		 for (int j = i + 1; j <= T; j++)
		 {
		 	   double chax = a[i].x - a[j].x;
		 	   double chay = a[i].y - a[j].y;
		 	   if (4 * x * x >= chax * chax + chay * chay) 
			   {
			       int XX = Find(i), YY = Find(j);
				   if (XX != YY) fa[XX] = YY;
			   }
		 }
	for (int i = 1; i <= T; i++)
	{
	     int G = Find(i);
	     if (a[i].x <= x) e[G].A = 1; //上 
		 if (a[i].x + x >= n) e[G].C = 1; //下 
		 if (a[i].y <= x) e[G].B = 1; //左 
		 if (a[i].y + x >= m) e[G].D = 1; //右 
	} 
	for (int i = 1; i <= T; i++)
	{
		 int G = Find(i); 
	     if (e[G].A && e[G].B) return 0; //上左 
	     if (e[G].A && e[G].C) return 0; //上下 
	     if (e[G].B && e[G].D) return 0; //左右 
	     if (e[G].C && e[G].D) return 0; //下右 
    }
	return 1;
}
  
int main()
{
	freopen("AC.in", "r", stdin);
	freopen("AC.out", "w", stdout); 
    scanf("%lf %lf %d", &n, &m, &T);
	for (int i = 1; i <= T; i++) scanf("%lf %lf", &a[i].x, &a[i].y);
	double ans = 0, l = 0;
	double r = (double)sqrt(n * n + m * m); 
	while (l + eps <= r)
	{
		   double mid = (l + r) / 2;
	       if (Calc(mid)) ans = mid, l = mid + eps;
		             else r = mid; 	    
	}
	printf("%.2lf\n", ans);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值