- 题目
input
2
8 8
3 7
3
5 6
2 7
2 5
6 6
3 2
5
5 4
2 4
5 5
2 3
1 4
output
Case #1: 13.50000000
Case #2: 16.00000000
- 解题思路
这道题的样例暗示应该以Bob为顶点去求解。但是实际上,第一个样例的答案是错误的:
(来源:知乎用户cometeme的回答https://www.zhihu.com/question/426081900)
虽然这道题假了,但是还是试着以Bob为顶点过下这道题吧。
以Bob为顶点,和其他n个点做射线,此时相当于坐标系转变为Bob是原点。根据射线的极角和三角函数计算从x轴正半轴转到该射线的位置在四条边框上所截取的长度,分8中情况讨论。对这些长度排序,即相当于对极角排序。枚举两条相邻的射线a,b(包括尾、首射线),可以保证a->b之间是空白的(没有其他点),注意这里一定要保证是a到b的顺序,是有向的。a和b截取的长度做差即可求得结果,对于首尾射线特殊考虑下即可。(wjx的思路)
还有一种思路和上面类似,对所有射线极角排序(因为可能出现相同极角的射线,根据后面的算法,必须去重),对四条边框依次标号。根据三角形相似求出相邻两条射线和边框的交点依次是A,B,考虑A,B在分别在哪条边框上,分16种情况,计算从A->B在边框上的有向距离。注意,一定是A->B,在同一条边框上时不是直接求|AB|。(syh的思路)
时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
我原本的思路是判断两个交点A、B的位置,分三种情况:同一条边框,相邻边框、平行边框。但是这么分情况的话在算A->B的有向距离时很可能出错,wa了很多次,wjx和syh的思路又清晰又100%正确,遂放弃我的思路(꒦_꒦) 。
- ac代码
wjx的代码上小改了一下,懒得重新写了。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const double eps = 1e-8;
const double pi = acos(-1.0);
int n;
double w, h, bx, by;
double cx, cy, dx, dy; // (cx,cy)矩形左下角,(dx,dy)矩形右上角
double a[maxn]; // 极角度数
int dcmp(double x)//精度三态函数(>0,<0,=0)
{
if (fabs(x) < eps) return 0; //等于
else return x < 0 ? -1 : 1;//小于,大于
}
double get_angle(double x, double y) // 计算点(x,y)对应极角
{
double ang = atan2(y, x);
if(dcmp(ang)<0) ang = 2*pi+ang;
return ang;
}
double get_length(double a) // 计算极角a对应的所截取长度(从点(dx,0)开始)
{
double res = 0;
if(a <= get_angle(dx, dy)) // 右边上段
return res + dx * tan(a);
else
res += dy;
if(a <= pi / 2) // 上边右段
return res + dx - dy * tan(pi / 2 - a);
else
res += dx;
if(a <= get_angle(cx, dy)) // 上边左段
return res + dy * tan(a - pi / 2);
else
res += (-cx);
if(a <= pi) // 左边上段
return res + dy - (-cx) * tan(pi - a);
else
res += dy;
if(a <= get_angle(cx, cy)) // 左边下段
return res + (-cx) * tan(a - pi);
else
res += (-cy);
if(a <= pi * 3 / 2) // 下边左段
return res + (-cx) - (-cy) * tan(pi * 3 / 2 - a);
else
res += (-cx);
if(a <= get_angle(dx, cy)) // 下边右段
return res + (-cy) * tan(a - pi * 3 / 2);
else
res += dx;
return res + (-cy) - dx * tan(pi * 2 - a); // 右边下段
}
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
int T, kase = 0;
scanf("%d", &T);
while(T--)
{
scanf("%lf%lf", &w, &h);
scanf("%lf%lf", &bx, &by);
scanf("%d", &n);
cx = 0 - bx;
cy = 0 - by;
dx = w - bx;
dy = h - by;
for(int i = 1; i <= n; i++)
{
double x, y;
scanf("%lf%lf", &x, &y);
a[i] = get_length(get_angle(x - bx, y - by));
}
sort(a + 1, a + n + 1);
double ans = 0;
for(int i = 1; i < n; i++)
ans = max(ans, a[i+1] - a[i]);
ans = max(ans, 2 * (w + h) - (a[n] - a[1]));
printf("Case #%d: %.8f\n", ++kase, ans);
}
return 0;
}
/*
6
8 8
3 7
3
5 6
2 7
2 5
6 6
3 2
5
5 4
2 4
5 5
2 3
1 4
4 4
2 2
2
1 1
3 3
4 4
2 2
1
1 1
5 5
3 3
2
1 1
2 2
4 3
1 1
2
1 2
2 2
4 3
1 1
2
1 2
2 2
*/