JZOJ 5904【NOIP2018模拟10.15】刺客信条

版权声明:并没卵用的版权声明~喜欢的就在评论区聊聊天吧~~ https://blog.csdn.net/Frocean/article/details/83089182

昨晚改出来了 被墙联通坑死了 手改大数据......

先放题目

Description

          故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客。最终,凭借着他的努力和出众的天赋,成为了杰出的刺客大师。刺客组织在他的带领下,为被剥削的平民声张正义,赶跑了原本统治意大利的圣殿骑士首领-教皇亚历山大六世。在他的一生中,经历了无数次惊心动魄、扣人心弦的探险和刺杀。
        这次的故事就是他暗杀一位作恶多端的红衣主教。红衣主教可以吸取他周围人的生命力量,而他的红衣教徒也拥有这个力量。红衣主教的家是一个x*y 的长方形房间,也就是说,他的家的四个角坐标分别为(0,0)(x,0)(0,y)(x,y)。教堂的门在(0,0) ,而红衣主教就在 (x,y)的卧室休息。他的家中还有n个守护着他的红衣教徒,站在(ai,bi)。Ezio想要趁主教休息时,从门进入潜入到他的卧室刺杀他,因为主教休息时会脱下红衣,这样吸取生命的力量就消失了。可是守卫他的红衣教徒依然很危险,离红衣教徒太近就会被吸取生命。因此,Ezio想知道,在能刺杀主教的前提,从门到他的卧室的路上,他最远和离他最近的红衣教徒保持多远的距离。注意:教徒都在房间里。

Input

第一行三个整数x,y,n。之后n行,每行两个整数ai,bi ,意义见题目描述。

Output

一行一个数D,表示Ezio能保持的最大距离,保留两位小数。

Sample Input

10 20 2
3 3
6 14

Sample Output

3.00

样例说明
贴着墙走

Data Constraint

数据范围
对 10%的数据n<=10,
 对 30%的数据n<=100
对 100%的数据n<=2000
保证输入合法,x,y属于[1,10^6]

这题和去年PION提高的奶酪很像啊虽然当时我是没想出来 先放一波官方题解

我再来解释一波

起点终点断开 则 左边 上面 的墙是连起来的 右边 下面的墙是连起来的 但左上 右下两墙是分开的

我们想办法把这两墙连起来 因为当他连起来以后 起点和终点就分开了 这时这个边集最大值就是最大距离

虽然求最大距离 但我们要从小加边权 为什么呢

当起点终点刚好分开的时候 我们肯定只有一条从一墙到另一墙的路 这时我们选这堆边集里的最大值 用以穿过这个边集

如果我们从大加 万一还有边集 that (定语从句) 最大值比他小的 也可以联通 那就也要穿过这个边集

所以我们从小找答案的话 就不用更新答案了嘛

还有 每个点都要向两个墙连边 而且是取 点 到 每个墙的两个墙 的 最小距离

inline void addedge(int node) {
	e[++tot].u = node,e[tot].v = n + 1,e[tot].w = min(s[node].x,y - s[node].y) * 2,e[tot].w *= e[tot].w;
	//注意这里取min的是哪两个值 一定要注意啊QvQ
	e[++tot].u = node,e[tot].v = n + 2,e[tot].w = min(s[node].y,x - s[node].x) * 2,e[tot].w *= e[tot].w;
}

我这里有点奇怪 因为两点之间距离是 \frac{\sqrt{(a^{2} + b^{2})}}{2} 而墙却不用

为了避免 sqrt 的多次运算 我把墙和点的距离就乘起来了...不过还是差不多一样的速度700+ms为什么我们这边的dalao可以跑21ms啊 然后答案要记得除回去

下放很正常的两个代码

//sqrt后置版
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 2010;
struct human{double x,y;}s[MAXN];
struct edge{double w;int u,v;}e[MAXN * MAXN];
double x,y,ans;
int l[MAXN],n,tot;
inline double min(double i,double j) {return i < j ? i : j;}
inline int f(int p) {return l[p] == p ? p : l[p] = f(l[p]);}
inline short cmp(edge i,edge j) {return i.w < j.w;}
inline void addedge(int node) {
	e[++tot].u = node,e[tot].v = n + 1,e[tot].w = min(s[node].x,y - s[node].y) * 2,e[tot].w *= e[tot].w;
	e[++tot].u = node,e[tot].v = n + 2,e[tot].w = min(s[node].y,x - s[node].x) * 2,e[tot].w *= e[tot].w;
}
inline double dis(int i,int j) {
	double a = abs(s[i].x - s[j].x);
	double b = abs(s[i].y - s[j].y);
	return a * a + b * b;
}
inline short pd()
{
	int a = f(n - 1),b = f(n);
	if (a == b) return 0;
	return 1;
}
int main()
{
	freopen("AC.in","r",stdin);
	freopen("AC.out","w",stdout);
	scanf("%lf%lf%d",&x,&y,&n);
	for (int a = 1 ; a <= n ; ++ a) scanf("%lf%lf",&s[a].x,&s[a].y);
	for (int a = 1 ; a <= n ; ++ a) addedge(a);
	for (int a = 2 ; a <= n ; ++ a)
	for (int b = 1 ; b <  a ; ++ b)
	e[++tot].u = a,e[tot].v = b,e[tot].w = dis(a,b);
	sort(e + 1,e + tot + 1,cmp),n += 2;
	for (int a = 1 ; a <= n ; ++ a) l[a] = a;
	for (int a = 1,o = 1 ; a <= tot && pd() ; ++ a)
	{
		int i = f(e[a].u);
		int j = f(e[a].v);
		if (i == j) continue;
		l[j] = i,++o;
		ans = max(ans,e[a].w);
	}
	printf("%.2lf\n",sqrt(ans) / 2);
	fclose(stdin);
	fclose(stdout);
	return 0;
}



//Frocean原版
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 2010;
struct human{double x,y;}s[MAXN];
struct edge{double w;int u,v;}e[MAXN * MAXN];
double x,y,ans;
int l[MAXN],n,tot;
inline double min(double i,double j) {return i < j ? i : j;}
inline int f(int p) {return l[p] == p ? p : l[p] = f(l[p]);}
inline short cmp(edge i,edge j) {return i.w < j.w;}
inline void addedge(int node) {
	e[++tot].u = node,e[tot].v = n + 1,e[tot].w = min(s[node].x,y - s[node].y);
	e[++tot].u = node,e[tot].v = n + 2,e[tot].w = min(s[node].y,x - s[node].x);
}
inline double dis(int i,int j) {
	double a = abs(s[i].x - s[j].x);
	double b = abs(s[i].y - s[j].y);
	return sqrt(a * a + b * b) / 2;
}
inline short pd()
{
	int a = f(n - 1),b = f(n);
	if (a == b) return 0;
	return 1;
}
int main()
{
	freopen("AC.in","r",stdin);
	freopen("AC.out","w",stdout);
	scanf("%lf%lf%d",&x,&y,&n);
	for (int a = 1 ; a <= n ; ++ a) scanf("%lf%lf",&s[a].x,&s[a].y);
	for (int a = 1 ; a <= n ; ++ a) addedge(a);
	for (int a = 2 ; a <= n ; ++ a)
	for (int b = 1 ; b <  a ; ++ b)
	e[++tot].u = a,e[tot].v = b,e[tot].w = dis(a,b);
	sort(e + 1,e + tot + 1,cmp),n += 2;
	for (int a = 1 ; a <= n ; ++ a) l[a] = a;
	for (int a = 1,o = 1 ; a <= tot && pd() ; ++ a)
	{
		int i = f(e[a].u);
		int j = f(e[a].v);
		if (i == j) continue;
		l[j] = i,++o;
		ans = max(ans,e[a].w);
	}
	printf("%.2lf\n",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Frocean/article/details/83089182