一道计算几何的神题,复(xue)习了各种计算几何的基础知识
先上题解
将航线上的每一段线段加入循环队列
对于每一个线段l,r,求出到l最近的点p1和到r最近的点p2.在线段l,r内找出和p1,p2长度相等的点p,设所有陆地与p的最近点为p3,那么线段[l,p]和[p,r]的答案不会超过max(len(l,p1),len(p,p3),len(r,p2)),也就是如果这个值小于当前答案的话,线段上任意一点不会更新答案,否则将[l,p],[p,r]加入循环队列
注意,如果达到精度要求就不用继续计算了,否则会死循环。
复习了以下知识点:
点积,叉积,向量的模长
点在线上的判定 33' bool on
线段相交的判定 39' bool inter
点在多边形内的判定 48' bool in
点到线段的距离 61' double dis
点到线段最近点的求法 70' getit
总之,这还是一道计算几何的好题
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define md
#define ll long long
#define inf (int) 1e9
#define eps 1e-8
#define N
using namespace std;
struct point { double x,y;} xian[25];
struct line {point x,y;} q[1000010];
struct near {point x;double dis;};
const int maxn=1000000;
int n,m;
double ans=0;
inline double sqr(double a) { return a*a;}
int fcmp(double a,double b)
{
if (a-b>eps) return 1;
if (a-b<-eps) return -1;
return 0;
}
double dot(point a,point b) { return a.x*b.x+a.y*b.y;}
bool operator ==(point a,point b) { point p=(point){a.x-b.x,a.y-b.y}; return fcmp(p.x,0)==0&&fcmp(p.y,0)==0;}
double operator * (point a,point b) { return a.x*b.y-a.y*b.x;}
point operator * (point a,double b) { return (point){a.x*b,a.y*b};}
point operator / (point a,double b) { return (point) {a.x/b,a.y/b};}
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};}
inline double len(point a) { return sqrt(a.x*a.x+a.y*a.y);}
bool on (point a,point b,point c)
{
if (a==b||a==c) return 1;
return (fcmp((a-b)*(c-b),0)==0&&fcmp(dot(a-b,a-c),0)<0);//
}
bool inter(point a,point b,point c,point d)
{
return fcmp(((b-a)*(c-a))*((b-a)*(d-a)),0)<0&&fcmp(((d-c)*(a-c))*((d-c)*(b-c)),0)<0;
}
struct LAND
{
int tot;
point a[35];
bool in(point x)
{
for (int i=1;i<=tot;i++)
if (on(x,a[i],a[i+1])) return 1;
x.y+=0.1;
point p=(point){-10001,x.y+0.1};
int jiao=0;
for (int i=1;i<=tot;i++) jiao+=inter(p,x,a[i],a[i+1]);
x.y-=0.1;
return jiao&1;
}
}land[25];
inline double dis(point a,line b)
{
point p1=a-b.x,p2=b.y-b.x,p3=a-b.y,p4=b.x-b.y;
if (b.x==b.y) return len(p1);
if (fcmp(dot(p1,p2),0)<0) return len(p1);
if (fcmp(dot(p3,p4),0)<0) return len(p3);
return (p1*p2/len(p2));
}
inline near getit(point a,point b,point c)
{
point p1=a-b,p2=c-b,p3=a-c,p4=b-c;
if (b==c) return (near){b,len(p1)};
if (fcmp(dot(p1,p2),0)<=0) return (near){b,len(p1)};
if (fcmp(dot(p3,p4),0)<=0) return (near){c,len(p3)};
double t=dot(p1,p2)/dot(p2,p2);
point d=b+p2*t; return (near){d,len(d-a)};
}
near find(point x)
{
for (int i=1;i<=n;i++) if (land[i].in(x)) return (near){x,0};
double mlen=inf;
near xans=(near){x,inf};
for (int i=1;i<=n;i++)
{
for (int j=1;j<=land[i].tot;j++)
{
near now=getit(x,land[i].a[j],land[i].a[j+1]);
if (fcmp(now.dis,xans.dis)<=0) xans=now;
}
}
ans=max(ans,xans.dis);
return xans;
}
void solve()
{
ans=0;
int h=0,w=0;
for (int i=1;i<m;i++)
q[++w]=(line){xian[i],xian[i+1]};
for (int i=1;i<=m;i++) find(xian[i]);
while (h!=w)
{
h++; if (h>maxn+2) h=1;
line L=q[h];
near p1=find(L.x),p2=find(L.y);
point l=L.x,r=L.y;
while (len(l-r)>(1e-4))
{
point mid=(l+r)/2;
int bo=fcmp(len(mid-p1.x),len(mid-p2.x));
if (bo==1) r=mid;
else if (bo==0) l=r=mid;
else l=mid;
}
double nowans=max(len(l-p1.x),len(l-p2.x));
near p=find(l);
if (ans+0.004<nowans)
{
line L1=(line){L.x,l},L2=(line){l,L.y};
w++; if (w>maxn+2) w=1; q[w]=L1;
w++; if (w>maxn+2) w=1; q[w]=L2;
}
}
}
point read() { point a; scanf("%lf%lf",&a.x,&a.y); return a;}
int main()
{
//freopen("1020.in","r",stdin); freopen("1020.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) xian[i]=read();
for (int i=1;i<=n;i++)
{
scanf("%d",&land[i].tot);
for (int j=1;j<=land[i].tot;j++) land[i].a[j]=read();
land[i].a[land[i].tot+1]=land[i].a[1];//?
}
solve();
printf("%.2lf\n",ans);
return 0;
}