#半平面交,BFS#洛谷 3297 [SDOI2013] 逃考

题目传送门


分析

其实关注的应该是人所在的区域,使得最后到达边界外的区域。

而区域之间的边界是两个点的中垂线,

因此对于每个点把这些线以及四条边界求半平面交得到真正的边界,

相邻的区域两两连边跑 BFS 即可。


代码

#include <cstdio>
#include <cmath>
#include <cctype>
#include <queue>
#include <algorithm>
using namespace std;
const int N=611; struct node{int y,next;}e[N*N];
struct Point{
	double x,y;
	Point operator -(const Point &t)const{
	    return (Point){x-t.x,y-t.y};
	}
}P[N],S,T;
double cj(Point x,Point y){return x.x*y.y-x.y*y.x;}
struct line{
	Point a,b; double theta; int id;
	bool operator <(const line &t)const{
	    return theta<t.theta||(theta==t.theta&&cj(b-a,t.a-a)>0);
	}
}a[N],A[N],b[N];
int head,tail,n,_n,dis[N],v[N],as[N],et; double ans;
int iut(){
    int ans=0,f=1; char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans*f;
}
double dist(Point x){return sqrt(x.x*x.x+x.y*x.y);}
Point inter(line x,line y){
	double S1=cj(y.a-x.a,y.b-x.a),S2=cj(y.b-x.b,y.a-x.b),S0=S1/(S1+S2);
	return (Point){x.a.x+S0*(x.b.x-x.a.x),x.a.y+S0*(x.b.y-x.a.y)};
}
bool check(line x,line y,line z){
	Point p=inter(x,y);
	return cj(p-z.a,z.b-z.a)>0;
}
void Half_Plane(){
	int m; a[m=1]=A[1];
	for (int i=2;i<=_n;++i){
	    if (A[i].theta!=a[m].theta) ++m;
	    a[m]=A[i];
	}
	b[head=1]=a[1],b[tail=2]=a[2];
	for (int i=3;i<=m;++i){
		while (head<tail&&check(b[tail-1],b[tail],a[i])) --tail;
		while (head<tail&&check(b[head+1],b[head],a[i])) ++head;
		b[++tail]=a[i];
	}
	while (head<tail&&check(b[tail-1],b[tail],b[head])) --tail;
	while (head<tail&&check(b[head+1],b[head],b[tail])) ++head;
}
void doit(int now){
    _n=0;
    A[++_n].a=(Point){T.x,0.0},A[_n].b=(Point){T.x,T.y},A[_n].id=n+1;
    A[++_n].a=(Point){T.x,T.y},A[_n].b=(Point){0.0,T.y},A[_n].id=n+1;
    A[++_n].a=(Point){0.0,T.y},A[_n].b=(Point){0.0,0.0},A[_n].id=n+1;
    A[++_n].a=(Point){0.0,0.0},A[_n].b=(Point){T.x,0.0},A[_n].id=n+1;
    for (int i=1;i<=n;++i)
    if (now!=i){
        Point mid=(Point){(P[i].x+P[now].x)/2,(P[i].y+P[now].y)/2};
        A[++_n].a=mid-(Point){P[now].y-mid.y,mid.x-P[now].x};
        A[_n].b=mid,A[_n].id=i;
    }
    for (int i=1;i<=_n;++i) A[i].theta=atan2(A[i].b.y-A[i].a.y,A[i].b.x-A[i].a.x);
	sort(A+1,A+1+_n),Half_Plane();
	if (tail-head<=1) return;
	for (int i=head;i<=tail;++i)
	    e[++et]=(node){b[i].id,as[now]},as[now]=et;
}
void bfs(int S){
    queue<int>q; q.push(S);
    v[S]=1,dis[S]=0;
    while (!q.empty()){
        int x=q.front(); q.pop();
        for (int i=as[x];i;i=e[i].next)
        if (!v[e[i].y]){
            v[e[i].y]=1,dis[e[i].y]=dis[x]+1;
            q.push(e[i].y);
        }
    }
}
int main(){
    for (int Test=iut();Test;--Test){
        n=iut(),T.x=iut(),T.y=iut(),S.x=iut(),S.y=iut(),et=0;
        for (int i=1;i<=n;++i){
            P[i].x=iut(),P[i].y=iut();
            if (P[i].x<0||P[i].y<0||P[i].x>T.x||P[i].y>T.y) --i,--n;
        }
        if (!n){
            printf("0\n");
            continue;
        }
        int st=1;
        for (int i=2;i<=n;++i)
            if (dist(S-P[i])<dist(S-P[st])) st=i;
        for (int i=1;i<=n;++i) doit(i);
        bfs(st);
        printf("%d\n",dis[n+1]);
        for (int i=1;i<=n+1;++i) dis[i]=v[i]=as[i]=0;
    }
	return 0;
}
posted @ 2025-07-06 07:53  lemondinosaur  阅读(10)  评论(0)    收藏  举报