您的位置:首页 > 其它

bzoj 1020 计算几何

2016-08-17 18:35 381 查看
题意:一堆多边形,一个折线。求折线上的点离多边形最远距离。

听说莫涛的论文写了这道题?

先把折线中所有的线段用多边形截,把不在多边形内的线段塞到一个队列里。

遍历队列,对于一个线段求出左端点到多边形的最近点p1,右端点到多边形的最近点p2。

分别用左右端点到p1,p2的距离更新答案。在线段上二分一个点p使dis(p,p1)=dis(p,p2)。

如果dis(p,p1)>ans那么把当前线段从p分成两段塞回队列。

并不会证明,但是这玩意跑得飞快。

#include <bits/stdc++.h>
using namespace std;
#define ppi pair<poi,int>
#define eps 1e-9
#define inf 1e9
int c,n,cnt;
double ans;
const double e=exp(1),pi=acos(-1);
int dcmp(double x)
{
if(x<-eps)return -1;
if(x>eps)return 1;
return 0;
}
struct poi
{
double x,y;
poi(){}
poi(double x,double y):x(x),y(y){}
friend bool operator < (const poi &p1,const poi &p2)
{
if(!dcmp(p1.x-p2.x))return p1.y<p2.y;
return p1.x<p2.x;
}
void read(){scanf("%lf%lf",&x,&y);}
friend poi operator - (const poi &p1,const poi &p2)
{return poi(p1.x-p2.x,p1.y-p2.y);};
friend poi operator + (const poi &p1,const poi &p2)
{return poi(p1.x+p2.x,p1.y+p2.y);};
friend double operator * (const poi &p1,const poi &p2)
{return p1.x*p2.x+p1.y*p2.y;};
friend double operator ^ (const poi &p1,const poi &p2)
{return p1.x*p2.y-p2.x*p1.y;};
friend poi operator * (double x,const poi &p1)
{return poi(p1.x*x,p1.y*x);};
}v[2100];
double dis(poi p1,poi p2)
{return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);}
struct line
{
poi p1,p2,v;
line(){}
line(poi p1,poi p2):p1(p1),p2(p2){v=p1-p2;}
poi mid(){return poi((p1.x+p2.x)/2,(p1.y+p2.y)/2);}
}a[51];
queue<line>que;
int online(line l1,poi p1)
{return dcmp((p1-l1.p1)*(p1-l1.p2))<=0;}
ppi intersect(line l1,line l2)
{
l1.v=l1.p1-l1.p2;
l2.v=l2.p1-l2.p2;
poi u=l1.p1-l2.p1;
double tmp=(u^l2.v)/(l2.v^l1.v);
poi p=l1.p1+tmp*l1.v;
return make_pair(p,online(l1,p)&&online(l2,p));
}
struct poly
{
int m;
poi p[51];
line l[51];
void read()
{
scanf("%d",&m);
for(int i=1;i<=m;i++)p[i].read();
p[m+1]=p[1];
for(int i=1;i<=m;i++)l[i]=line(p[i],p[i+1]);
}
void cal(line l1)
{
for(int i=1;i<=m;i++)
{
ppi p1=intersect(l[i],l1);
if(p1.second)v[++cnt]=p1.first;
}
}
int in(poi p1)
{
int cnt=0;
line l1=line(p1,poi(p1.x+e*inf,p1.y+pi*inf));
for(int i=1;i<=m;i++)
cnt+=intersect(l1,l[i]).second;
return cnt&1;
}
poi get(poi p1)
{
poi ret=poi(inf,inf);
for(int i=1;i<=m;i++)
{
ret=dis(ret,p1)<dis(l[i].p1,p1) ? ret:l[i].p1;
ret=dis(ret,p1)<dis(l[i].p2,p1) ? ret:l[i].p2;
poi p2=poi(p1.x-l[i].p2.y+l[i].p1.y,p1.y+l[i].p2.x-l[i].p1.x);
ppi p=intersect(l[i],line(p1,p2));
if(online(l[i],p.first))
ret=dis(ret,p1)<dis(p.first,p1) ? ret:p.first;
}
return ret;
}
}b[51];
int main()
{
//freopen("tt.in","r",stdin);
scanf("%d%d",&c,&n);
for(int i=1;i<n;i++)a[i].p1.read();
a[n-1].p2.read();
for(int i=1;i<n-1;i++)a[i].p2=a[i+1].p1;
for(int i=1;i<=c;i++)b[i].read();
for(int i=1;i<n;i++)
{
v[cnt=1]=a[i].p1;
for(int j=1;j<=c;j++)
b[j].cal(a[i]);
v[++cnt]=a[i].p2;
sort(v+1,v+1+cnt);
for(int j=1;j<cnt;j++)
if(dcmp(dis(v[j],v[j+1]))>0)
{
int flag=0;
for(int k=1;k<=c;k++)
if(b[k].in(line(v[j],v[j+1]).mid()))
{flag=1;break;}
if(!flag)que.push(line(v[j],v[j+1]));
}
}
while(!que.empty())
{
line l1=que.front();
que.pop();
poi p1=poi(inf,inf),p2=p1;
for(int i=1;i<=c;i++)
{
poi p=b[i].get(l1.p1);
p1=dis(p1,l1.p1)<dis(p,l1.p1) ? p1:p;
p=b[i].get(l1.p2);
p2=dis(p2,l1.p2)<dis(p,l1.p2) ? p2:p;
}
ans=max(ans,sqrt(dis(p1,l1.p1)));
ans=max(ans,sqrt(dis(p2,l1.p2)));
poi l=l1.p1,r=l1.p2;
while(dcmp(dis(l,r))>0)
{
poi mid=line(l,r).mid();
if(dis(mid,p1)<dis(mid,p2))l=mid;
else r=mid;
}
if(sqrt(dis(l,p1))>ans+0.001)
{
que.push(line(l,l1.p1));
que.push(line(l,l1.p2));
}
}
printf("%.2lf\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  计算几何