洛谷传送门
题目描述
髙考又来了,对于不认真读书的来讲真不是个好消息为了小杨能在家里认真读书,他 的亲戚决定驻扎在他的家里监督他学习,有爷爷奶奶、外公外婆、大舅、大嫂、阿姨……
小杨实在是忍无可忍了,这种生活跟监狱有什么区别!为了他亲爱的小红,为了他的 dota,他决定越狱!
假设小杨的家是个 n×m n × m 的矩阵,左下角坐标为 (0,0) ( 0 , 0 ) ,右上角坐标为 (xl,yl) ( x l , y l ) 。小 杨有n个亲戚,驻扎在矩阵里(位置不同,且不在矩阵的边上)。小杨家里的每个地方都被 亲戚监控着,而且只被距离最近的亲戚监控:
也就是说假设小杨所在的位置是 (3,3) ( 3 , 3 ) ,亲戚A在 (3,0) ( 3 , 0 ) , A距离小杨距离是3;亲戚 B在 (6,7) ( 6 , 7 ) ,则B距离小杨距离是5。距离A<距离B,所以 (3,3) ( 3 , 3 ) 位置由A监控。
如果“最近距离”出现同时有几个亲戚,那么那个位置同时被那几个亲戚监控。
给出小杨的坐标 (x0,y0) ( x 0 , y 0 ) 。因为发现的人数越少,越狱成功的机会越大,所以小杨需要你设计一条越狱路线到达矩形的边上,且被发现的人数最少。
Ps:小杨做的方向是任意的,也就是说路线上的任意位置H需耍是实数。
保证一开始小杨只被一个亲戚监控着。
输入输出格式
输入格式:
第一行 一个正整数 t<=3 t <= 3 表示数据组数
接下来t个数据:
第一行n表示亲戚个数
第二行4个正整数表示举行右上角坐标 (x1,y1) ( x 1 , y 1 ) 和小杨的坐标 (x0,y0) ( x 0 , y 0 )
接下来n行,每行2个正整数表示一个亲戚的位置
输出格式:
每个数据一个正整数表示越狱被发现人数的最小值
输入输出样例
输入样例:
2
4
10 10 5 5
5 6
3 5
7 5
5 3
17
14 12 7 6
7 11
6 9
7 7
1 10
2 20
1 6
2 6
1 1
2 2
5 1
5 2
13 1
12 2
12 7
13 7
12 11
13 11
输出样例:
1
2
说明
数据解释:
第一个数据, 小杨直接往上走,只被 (5,6) ( 5 , 6 ) 监控过.
第二个数据,小杨被 (7,7) ( 7 , 7 ) 监控- 走到 (9,9) ( 9 , 9 ) 被 (7,11) ( 7 , 11 ) 监控, 然后直接往上走.
数据规模:
前 50%数据. n<=200 n <= 200 ;
其余数据 n<=600 n <= 600 .
解题分析
先给大家看一张妙妙的图
设矩阵范围为
□ABCD
◻
A
B
C
D
, 亲戚为
E,F,G,H
E
,
F
,
G
,
H
,显然对于每个亲戚, 都有一定的控制范围(用色块表示), 而我们肯定不会走有多个亲戚同时监控的点(矩阵内部色块夹角处)
那么我们可以 O(N2log(N)) O ( N 2 l o g ( N ) ) 预处理出每个亲戚相邻的亲戚, 再建图连边跑最短路即可。 对于每个控制范围与边界相交的亲戚,我们连一条到终点的边。 起点只需要在输入坐标时比较距离即可。
打板即可。
代码:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <algorithm>
#define R register
#define gc getchar()
#define IN inline
#define W while
#define MX 1005
#define EPS 1e-8
#define db double
int num, st, ed, lcnt, head, tail;
db rig, up, now_x, now_y, min_dis;
namespace Geometry
{
using std::sort;
bool out[MX];
struct pt
{
db x, y;
}man[MX], inter[MX];
IN pt operator + (const pt &x, const pt &y) {return (pt){x.x + y.x, x.y + y.y};}
IN pt operator - (const pt &x, const pt &y) {return (pt){x.x - y.x, x.y - y.y};}
IN db operator * (const pt &x, const pt &y) {return x.x * y.y - x.y * y.x;}
IN db operator / (const pt &x, const pt &y) {return x.x * y.x + x.y * y.y;}
IN pt operator * (const pt &x, const db &y) {return (pt){x.x * y, x.y * y};}
IN pt operator / (const pt &x, const db &y) {return (pt){x.x / y, x.y / y};}
IN pt get_mid (const pt &x, const pt &y) {return (pt){(x.x + y.x) / 2.0, (x.y + y.y) / 2.0};}
IN db get_dis (const pt &x) {return sqrt(x.x * x.x + x.y * x.y);}
IN int sig (const db &x) {return (x > -EPS) - (x < EPS);}
IN bool operator < (const pt &x, const pt &y) {return x.x == y.x ? x.y < y.y : x.x < y.x;}
IN pt rotate (const pt &x) {return (pt){-x.y, x.x};}
struct line
{
pt a, b;
db ang;
int id;
line(){}
line(pt x, pt y, int t): a(x), b(y), id(t){ang = atan2(b.y - a.y, b.x - a.x);}
}lin[MX], que[MX];
IN bool operator < (const line &x, const line &y) {return x.ang < y.ang;}
IN pt get_int(const line &x, const line &y)
{
db k1 = (y.b - x.a) * (x.b - x.a);
db k2 = (x.b - x.a) * (y.a - x.a);
return (y.b - y.a) * (k2 / (k1 + k2)) + y.a;
}
IN bool onleft (const line &x, const pt &y)
{return (x.b - x.a) * (y - x.a) > EPS;}
}
namespace SPFA
{
using std::queue;
int hd[MX], dist[MX];
bool inq[MX];
queue <int> q;
struct Edge
{
int to, nex;
}edge[MX * 100];
int cnt;
IN void addedge(const int &from, const int &to)
{
edge[++cnt] = (Edge){to, hd[from]};
hd[from] = cnt;
edge[++cnt] = (Edge){from, hd[to]};
hd[to] = cnt;
}
int spfa()
{
memset(dist, 63, sizeof(dist));
dist[st] = 0;
q.push(st);
R int now;
W (!q.empty())
{
now = q.front();
q.pop();
for (R int i = hd[now]; i; i = edge[i].nex)
{
if(dist[edge[i].to] > dist[now] + 1)
{
dist[edge[i].to] = dist[now] + 1;
if(!inq[edge[i].to])
{
inq[edge[i].to] = false;
q.push(edge[i].to);
}
}
}
inq[now] = false;
}
return dist[ed];
}
}
using namespace Geometry;
using namespace SPFA;
void reset()
{
memset(out, false, sizeof(out));
memset(hd, 0, sizeof(hd));
min_dis = 1e9;
}
int main(void)
{
int T;
scanf("%d", &T);
W (T--)
{
reset();
scanf("%d", &num);
ed = num + 1;
scanf("%lf%lf%lf%lf", &rig, &up, &now_x, &now_y);
if(!num)
{printf("0\n"); continue;}
for (R int i = 1; i <= num; ++i)
{
scanf("%lf%lf", &man[i].x, &man[i].y);
if(man[i].x > rig || man[i].x < 0 || man[i].y <0 || man[i].y > up) out[i] = true;
db dis = get_dis(man[i] - (pt){now_x, now_y});
if(dis < min_dis) min_dis = dis, st = i;
}
for (R int i = 1; i <= num; ++i)
{
if(out[i]) continue;
lin[0] = line((pt){0, up}, (pt){0, -1}, ed);
lin[1] = line((pt){0, 0}, (pt){1, 0}, ed);
lin[2] = line((pt){rig, 0}, (pt){rig, up}, ed);
lin[3] = line((pt){rig, up}, (pt){-1, up}, ed);
lcnt = 3;
for (R int j = 1; j <=num; ++j)
{
if(i == j || out[j]) continue;
pt mid = get_mid(man[i], man[j]);
pt rot = mid + rotate(man[j] - mid);
lin[++lcnt] = line(mid, rot, j);
}
sort(lin, lin + lcnt + 1);
head = tail = 0;
que[0] = lin[0];
for (R int j = 1; j <= lcnt; ++j)
{
W (head < tail && !onleft(lin[j], inter[tail - 1])) --tail;
W (head < tail && !onleft(lin[j], inter[head])) ++head;
que[++tail] = lin[j];
if(!sig((que[tail - 1].b - que[tail - 1].a) * (que[tail].b - que[tail].a)))
{
tail--;
if(onleft(que[tail], lin[j].a)) que[tail] = lin[j];
}
if(head < tail) inter[tail - 1] = get_int(que[tail], que[tail - 1]);
}
W (head < tail && !onleft(que[head], inter[tail - 1])) --tail;
if(tail - head <= 1) continue;
for (R int j = head; j <= tail; ++j) addedge(i, que[j].id);
}
printf("%d\n", spfa());
}
}