一个直接的想法:能否求出每个亲戚的监视范围(也就是说亲戚
i
i
的监视范围内任意一个点到 的距离都是最短的)。
考虑一个点
(x,y)
(
x
,
y
)
,它到亲戚
i
i
的距离比到亲戚 短的条件:
做线段
ij
i
j
的垂直平分线
l
l
,那么 到亲戚
i
i
的距离比到亲戚 短的条件就是
(x,y)
(
x
,
y
)
在直线
l
l
朝向点 的一侧的半平面内。
而求第
i
i
个亲戚的监视范围,就是对于所有的 ,做线段
ij
i
j
的垂直平分线,把这些直线放在一起求一遍半平面交(注意要加上矩形边界的
4
4
条直线)。
然后对于一对 ,如果
i
i
和 的监视范围有公共边,则连边
(i,j)
(
i
,
j
)
。
对于任何一个
i
i
,如果 的监视范围在矩形的边界上,则连边
(i,n+1)
(
i
,
n
+
1
)
。
(
n+1
n
+
1
是一个虚拟节点,表示矩形外的部分)
然后找出起始点所在的区域,用 BFS 求出最短路即可解决。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Edge(u) for (int e = adj[u], v; e; e = nxt[e])
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 625, M = 4e6 + 5;
int n, m, xl, yl, X0, Y0, ecnt, nxt[M], adj[N], go[M], S, H,
T, len, que[N], dis[N];
bool vis[N], conn[N][N];
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}
struct cyx {
double x, y; cyx() {} cyx(double _x, double _y) : x(_x), y(_y) {}
friend inline cyx operator + (cyx a, cyx b) {
return cyx(a.x + b.x, a.y + b.y);
}
friend inline cyx operator - (cyx a, cyx b) {
return cyx(b.x - a.x, b.y - a.y);
}
friend inline cyx operator * (cyx a, double b) {
return cyx(a.x * b, a.y * b);
}
friend inline cyx operator / (cyx a, double b) {
return cyx(a.x / b, a.y / b);
}
friend inline double operator * (cyx a, cyx b) {
return a.x * b.y - a.y * b.x;
}
} otz[N];
double dist(cyx a, cyx b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
struct pyz {
int id; cyx a, b; pyz() {} pyz(cyx x, cyx y, int i) : a(x), b(y), id(i) {}
cyx o() {return a - b;}
} a[N], b[N], Q[N];
cyx orz(pyz x, pyz y) {
double s1 = (x.a - y.a) * (x.a - y.b), s2 = (x.b - y.b) * (x.b - y.a);
return x.a + x.o() * s1 / (s1 + s2);
}
bool check1(pyz x, pyz y) {
double tmp = x.o() * y.o();
return tmp > 1e-8 || (fabs(tmp) <= 1e-8 && y.o() * (y.a - x.a) > 1e-8);
}
bool check2(pyz a, pyz b, pyz x) {
cyx y = orz(a, b); return fabs((x.a - y) * x.o()) <= 1e-8
|| (x.a - y) * x.o() > 1e-8;
}
bool para(pyz x, pyz y) {
cyx a = x.o(), b = y.o(), c = cyx(0, 0);
return a * b == 0 && fabs(dist(a, c) + dist(c, b) - dist(a, b)) > 1e-8;
}
bool comp(pyz x, pyz y) {
cyx p = x.o(), q = y.o();
if ((p.y < 0 || (p.y == 0 && p.x < 0))
&& (q.y > 0 || (q.y == 0 && q.x > 0))) return 1;
if ((p.y > 0 || (p.y == 0 && p.x > 0))
&& (q.y < 0 || (q.y == 0 && q.x < 0))) return 0;
return check1(x, y);
}
void solvecyx() {
int i, n = 0; sort(b + 1, b + m + 1, comp);
For (i, 1, m) if (i == 1 || !para(b[i], b[i - 1])) a[++n] = b[i];
Q[H = 1] = a[1]; Q[T = 2] = a[2]; For (i, 3, n) {
while (H < T && check2(Q[T - 1], Q[T], a[i])) T--;
while (H < T && check2(Q[H], Q[H + 1], a[i])) H++;
Q[++T] = a[i];
}
while (H < T && check2(Q[T - 1], Q[T], Q[H])) T--;
}
pyz midpyz(cyx a, cyx b, int id) {
cyx st = cyx((a.x + b.x) / 2, (a.y + b.y) / 2), delta = st - a;
delta = cyx(delta.y, -delta.x); return pyz(st, st + delta, id);
}
void getex(int x) {
int i; m = 0; For (i, 1, n) if (x != i) b[++m] = midpyz(otz[x], otz[i], i);
b[++m] = pyz(cyx(0, 0), cyx(xl, 0), -1);
b[++m] = pyz(cyx(xl, 0), cyx(xl, yl), -1);
b[++m] = pyz(cyx(xl, yl), cyx(0, yl), -1);
b[++m] = pyz(cyx(0, yl), cyx(0, 0), -1); solvecyx();
For (i, H, T) if (Q[i].id == -1) add_edge(x, n + 1);
else conn[x][Q[i].id] = 1; bool flag = 1; For (i, H, T)
if (fabs((Q[i].a - cyx(X0, Y0)) * Q[i].o()) <= 1e-8
|| (Q[i].a - cyx(X0, Y0)) * Q[i].o() > 1e-8) flag = 0;
if (flag) S = x;
}
int bfs() {
int i; dis[que[len = 1] = S] = 0; vis[S] = 1; For (i, 1, len) {
int u = que[i]; Edge(u) {
if (vis[v = go[e]]) continue; vis[v] = 1;
dis[que[++len] = v] = dis[u] + 1;
}
}
return dis[n + 1];
}
void work() {
int i, j; n = read(); xl = read(); yl = read(); X0 = read(); Y0 = read();
For (i, 1, n) otz[i].x = read(), otz[i].y = read(); S = n + 1;
if (X0 <= 0 || Y0 <= 0 || X0 >= xl || Y0 >= yl) return (void) puts("0");
ecnt = 0; memset(adj, 0, sizeof(adj)); memset(vis, 0, sizeof(vis));
memset(conn, 0, sizeof(conn)); For (i, 1, n) getex(i);
For (i, 1, n) For (j, i + 1, n) if (conn[i][j] && conn[j][i])
add_edge(i, j); printf("%d\n", bfs());
}
int main() {
int T = read(); while (T--) work();
return 0;
}