BZOJ 3199 Escape

Link

Solution

可以发现每个亲戚管辖的区域是由与其它亲戚连线的中垂线分界的半平面,分界线上是两人管辖,分界线交点处是3个及以上的人管辖。 如果不考虑交点的话,就是把相邻的半平面连一条权为1的边,跑最短路。 然后就被交点弄晕了。去翻题解,发现根本没有人单独考虑了交点的情况。 换个思路一想,因为贪心地不走交点至少不会更差,而且也不会出现只能走交点的情况。 剩下就好说了。

Tips

建立半平面的时候方向随便选的,查了一节课;onleft写错,查了一节课。还是要练习静态查错 被边界情况困扰的时候,想想这种边界是不是必须要被考虑(同SDOI2015道路修建)。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//Code by Lucida
#include<bits/stdc++.h>
#define get(x) scanf("%d",&x)
//#define debug(x) std::cout<<#x<<'='<<x<<std::endl
template <class T> inline bool chkmx(T &a,const T &b){return a<b?a=b,1:0;}
template <class T> inline bool chkmn(T &a,const T &b){return a>b?a=b,1:0;}
const int MAXN=600+10,MAXM=MAXN*MAXN;
using std::sort;
using std::queue;

typedef double ld;
const ld eps=1e-6;
const ld pi=acos(-1.0);
inline int fcmp(ld x)
{
if(-eps<x && x<eps) return 0;
return x<0?-1:1;
}
struct vec
{
ld x,y;
vec(){}
vec(ld x,ld y):x(x),y(y){}
};
typedef vec poi;
vec operator +(vec a,vec b){return vec(a.x+b.x,a.y+b.y);}
vec operator -(vec a,vec b){return vec(a.x-b.x,a.y-b.y);}
vec operator *(vec a,ld b){return vec(a.x*b,a.y*b);}
vec operator /(vec a,ld b){return vec(a.x/b,a.y/b);}
ld inner(vec a,vec b){return a.x*b.x+a.y*b.y;}
ld outer(vec a,vec b){return a.x*b.y-a.y*b.x;}
vec Rotate(vec a,ld rad){return vec(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));}
struct line
{
poi a;vec v;int id;ld ang;
line(){}
line(poi a,vec v):a(a),v(v){ang=atan2(v.y,v.x);}
bool operator <(const line& a) const
{
return ang<a.ang;//atan2(v.y,v.x)<atan2(a.v.y,a.v.x);
}
};
poi p[MAXN];line dvd[MAXN];int dcnt;
line NormalBisector(poi a,poi b)
{
return line((a+b)/2,Rotate(b-a,pi/2));
}
int width,height;
void BuildEdge(int cur,int n)
{
dcnt=0;
for(int i=1;i<=n;i++)
if(i!=cur)
{
dvd[++dcnt]=NormalBisector(p[cur],p[i]);
dvd[dcnt].id=i;
}
dvd[++dcnt]=line(poi(0,0),vec(1,0));dvd[dcnt].id=0;
dvd[++dcnt]=line(poi(0,height),vec(0,-1));dvd[dcnt].id=0;
dvd[++dcnt]=line(poi(width,0),vec(0,1));dvd[dcnt].id=0;
dvd[++dcnt]=line(poi(width,height),vec(-1,0));dvd[dcnt].id=0;
}
line Ql[MAXN];poi Qp[MAXN];int he,ta;
bool onleft(poi a,line b){return fcmp(outer(a-b.a,b.v))<0;}
bool paral(vec a,vec b){return fcmp(outer(a,b))==0;}
bool paral(line a,line b){return paral(a.v,b.v);}
poi Cross(line a,line b)
{
ld t=outer(a.a-b.a,b.v)/outer(b.v,a.v);
return a.a+a.v*t;
}
ld Dist(poi a,poi b){return sqrt(inner(a-b,a-b));}
bool online(poi a,line l){return paral(a-l.a,l.v);}
void Intersect()
{
sort(dvd+1,dvd+1+dcnt);
#define dist(a,b) (b-a+1)
Ql[he=ta=1]=dvd[1];
for(int i=2;i<=dcnt;i++)
{
while(dist(he,ta)>=2 && !onleft(Qp[ta-1],dvd[i]))
ta--;
while(dist(he,ta)>=2 && !onleft(Qp[he],dvd[i]))
he++;//没写。。:w
Ql[++ta]=dvd[i];
if(paral(Ql[ta-1],Ql[ta]))
{
ta--;
//if((!onleft(Qp[ta-1],dvd[i]))!=(onleft(dvd[i].a,Ql[ta]))) assert((!onleft(Qp[ta-1],dvd[i]))==(onleft(dvd[i].a,Ql[ta])));
//if(!onleft(Qp[ta-1],dvd[i]))交点不一定存在。
if(onleft(dvd[i].a,Ql[ta]))
Ql[ta]=dvd[i];
}
if(dist(he,ta)>=2)//需要判断
Qp[ta-1]=Cross(Ql[ta],Ql[ta-1]);
}
while(dist(he,ta)>=2 && !onleft(Qp[ta-1],Ql[he])) ta--;
#undef dist
}
struct Edge{int to,pre,v;}e[MAXM<<1];int id[MAXN],ec;
void Adde(int f,int t,int v)
{
e[++ec].to=t;e[ec].v=v;e[ec].pre=id[f];id[f]=ec;
}
int SP(int S)
{
static queue<int> Q;
static int dis[MAXN];static bool inq[MAXN];
memset(dis,31,sizeof(dis));memset(inq,0,sizeof(inq));
Q.push(S);inq[S]=1;dis[S]=0;
while(!Q.empty())
{
int cur=Q.front();Q.pop();inq[cur]=0;
for(int i=id[cur];i;i=e[i].pre)
{
int u=e[i].to;
if(chkmn(dis[u],dis[cur]+e[i].v) && !inq[u])
Q.push(u),inq[u]=1;
}
}
return dis[0];
}
void CLEAR()
{
memset(id,0,sizeof(id));ec=0;
}
void WORK()
{
CLEAR();
int n,x0,y0;get(n);
get(width),get(height),get(x0),get(y0);
if(n==0) {puts("0");return;}
poi S=poi(x0,y0);int block=1;
for(int i=1;i<=n;i++)
{
int x,y;get(x),get(y);
p[i].x=x,p[i].y=y;
if(fcmp(Dist(S,p[block])-Dist(S,p[i]))>0)
block=i;
}
for(int i=1;i<=n;i++)
{
BuildEdge(i,n);
Intersect();
for(line *ptr=Ql+he;ptr<=Ql+ta;++ptr)
Adde(i,ptr->id,1);
}
printf("%d\n",SP(block));
}
int main()
{
int T;get(T);
while(T--)WORK();
return 0;
}
/* AC Record(Bugs) *
* WA atan2
* * * * * * * * * */