[半平面交][最短路]JZOJ 3297 SDOI2013逃考
Posted mastervan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[半平面交][最短路]JZOJ 3297 SDOI2013逃考相关的知识,希望对你有一定的参考价值。
分析
我们可以发现两个亲戚之间的监事距离分界线就是他们的连线的中垂线
那么一个亲戚的监视范围就是他与其他亲戚的连线的中垂线围成的凸多边形
这就是半平面交啦
那么我们轻松3小时+地打完半平面交模板以后,我们可以发现题目要求的就是小杨经过的路线穿过半平面交的最少次数,则使半平面交相邻的亲戚连边权为1的边,跑最短路即可
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <queue> #include <memory.h> using namespace std; typedef double ld; const int N=6e2+10; const ld eps=1e-12; int dcmp(ld a) return a<-eps?-1:(a>eps?1:0); struct Point ld x,y; s,t,a[N]; struct Line Point p,v; ld angle; int id; friend bool operator < (Line a,Line b) return dcmp(a.angle-b.angle)<0; l[N]; int lcnt; struct Graph int v,nx; g[4*N*N]; int cnt,list[N],dis[N]; bool vis[N]; int T,n; Point operator + (Point a,Point b) return (Point)a.x+b.x,a.y+b.y; Point operator - (Point a,Point b) return (Point)a.x-b.x,a.y-b.y; Point operator * (Point a,ld b) return (Point)a.x*b,a.y*b; Point operator / (Point a,ld b) return (Point)a.x/b,a.y/b; ld Cross_Multi(Point a,Point b) return a.x*b.y-a.y*b.x; ld Dot_Multi(Point a,Point b) return a.x*b.x+a.y*b.y; Point Mid_Point(Point a,Point b) return (a+b)/2.0; Point Rotate(Point v) return (Point)-v.y,v.x; bool Left(Line l,Point b) return Cross_Multi(l.v,b-l.p)>0; void Add(int u,int v) g[++cnt]=(Graph)v,list[u];list[u]=cnt; g[++cnt]=(Graph)u,list[v];list[v]=cnt; void Pre_Process(int k) lcnt=0; l[++lcnt]=(Line)(Point)0,t.y,(Point)0,-1,atan2(-1,0),n+1; l[++lcnt]=(Line)(Point)0,0,(Point)1,0,atan2(0,1),n+1; l[++lcnt]=(Line)(Point)t.x,0,(Point)0,1,atan2(1,0),n+1; l[++lcnt]=(Line)t,(Point)-1,0,atan2(0,-1),n+1; for (int i=1;i<=n;i++) if (i!=k) Point mid=Mid_Point(a[i],a[k]),rt=Rotate(a[i]-a[k]); l[++lcnt]=(Line)mid,rt,atan2(rt.y,rt.x),i; int x=lcnt; sort(l+1,l+lcnt+1); Point Linecut(Line a,Line b) Point w=a.p-b.p; ld t=Cross_Multi(b.v,w)/Cross_Multi(a.v,b.v); return a.p+a.v*t; void Halfcut(int x) deque<Line> q; deque<Point> p; while (!q.empty()) q.pop_front(); while (!p.empty()) p.pop_front(); q.push_front(l[1]); for (int i=2;i<=lcnt;i++) while (!p.empty()&&!Left(l[i],p.back())) q.pop_back(),p.pop_back(); while (!p.empty()&&!Left(l[i],p.front())) q.pop_front(),p.pop_front(); if (dcmp(Cross_Multi(l[i].v,q.back().v))==0) if (Left(q.back(),l[i].p)) q.pop_back(); if (!q.empty()) p.pop_back(); p.push_back(Linecut(q.back(),l[i])); q.push_back(l[i]); else p.push_back(Linecut(q.back(),l[i])),q.push_back(l[i]); while (!p.empty()&&!Left(q.front(),p.back())) q.pop_back(),p.pop_back(); if (p.empty()) return; while (!q.empty()) Add(x,q.front().id); q.pop_front(); void BFS(int v0) queue<int> q; memset(dis,0x3f,sizeof dis);memset(vis,0,sizeof vis); while (!q.empty()) q.pop(); q.push(v0);dis[v0]=0;vis[v0]=1; while (!q.empty()) int u=q.front();q.pop(); for (int i=list[u];i;i=g[i].nx) if (dis[g[i].v]>dis[u]+1) dis[g[i].v]=dis[u]+1; if (!vis[g[i].v]) q.push(g[i].v); vis[g[i].v]=1; vis[u]=0; printf("%d\n",dis[n+1]); int main() for (scanf("%d",&T);T;T--) scanf("%d",&n); scanf("%lf%lf%lf%lf",&t.x,&t.y,&s.x,&s.y); if (!n) printf("0\n"); continue; int mx=2147483647,st; for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); if (mx>Dot_Multi(a[i]-s,a[i]-s)) mx=Dot_Multi(a[i]-s,a[i]-s); st=i; cnt=0;memset(list,0,sizeof list); for (int i=1;i<=n;i++) Pre_Process(i); Halfcut(i); BFS(st);
以上是关于[半平面交][最短路]JZOJ 3297 SDOI2013逃考的主要内容,如果未能解决你的问题,请参考以下文章