这道题目的思路,可以见莫涛的论文《迭代思想的应用》。
虽然已经很详细了,这里还是讲一下吧。
首先把原来的所有折线中的线段都加入队列。然后对于条线段(a,b),进行操作:
首先找出a到陆地的最近的点x(如果a在陆地内或边上,则x=a),以及和b最近的点y。然后考虑a,b上的一个特殊点p,使得px=py,简单的可以二分得到(或者用中垂线也可以?没有试过)。那么对于(a,b)上的任意一个点q,显然有q到陆地的最近距离<px(py),因为如果q在(a,p)上,那么qx<px;q在(p,b)上同理。因此线段(a,b)与陆地的最大值显然不会超过px。那么如果px<当前的ans,这条线段就可以无视辣!!否则拆成两条线段(a,p)(p,b)加入队列。
至于为什么时间复杂度是对的。我也不知道。。另外这道题目好像一片4k+。。好可怕啊。。然而写起来发现还是比较简单的也就2.7k+(我又来秀弱~\(≧▽≦)/~辣)。(关键是DeBug)
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#define eps 1e-4
#define N 105
#define M 1000005
using namespace std;
int n,m; double ans; struct point{ double x,y; }a[N];
struct disp{ point p; double dis; };
struct line{ point p1,p2; }h[M];
point operator -(point u,point v){
point t; t.x=u.x-v.x; t.y=u.y-v.y; return t;
}
double dot(point u,point v){ return u.x*v.x+u.y*v.y; }
double crs(point u,point v){ return u.x*v.y-u.y*v.x; }
double dist(point u,point v){ return sqrt(dot(u-v,u-v)); }
bool upon(point u,point v,point w){
return !crs(v-u,w-u) && (u.x-v.x)*(u.x-w.x)<=0 && (u.y-v.y)*(u.y-w.y)<=0;
}
bool havitr(point u,point v,point s,point t){
return crs(v-u,s-u)*crs(v-u,t-u)<=0 && crs(t-s,u-s)*crs(t-s,v-s)<=0;
}
point getitr(point u,point s,point v,point t){
double tmp=crs(t,u-v)/crs(s,t);
u.x+=s.x*tmp; u.y+=s.y*tmp; return u;
}
disp lss(disp u,disp v){ return (u.dis<v.dis)?u:v; }
struct land{
int tot; point p[N];
void init(){
scanf("%d",&tot); int i;
for (i=1; i<=tot; i++) scanf("%lf%lf",&p[i].x,&p[i].y);
p[tot+1]=p[1];
}
bool inside(point t){
int i,sum=0;
for (i=1; i<=tot; i++)
if (upon(t,p[i],p[i+1])) return 1;
point s=t; s.x=1e5;
for (i=1; i<=tot; i++)
if (havitr(s,t,p[i],p[i+1])) sum++;
return sum&1;
}
}b[N];
disp nearst(point u,point v,point w){
disp t;
if (v.x==w.x && v.y==w.y) t.p=v; else
if (dot(u-v,w-v)<=0) t.p=v; else
if (dot(u-w,v-w)<=0) t.p=w; else{
point s=v-w; swap(s.x,s.y); s.x=-s.x;
t.p=getitr(u,s,v,w-v);
}
t.dis=dist(t.p,u); return t;
}
point updata(point t){
disp tmp; int i,j;
for (i=1; i<=m; i++)
if (b[i].inside(t)) return t;
tmp.dis=1e20;
for (i=1; i<=m; i++)
for (j=1; j<=b[i].tot; j++)
tmp=lss(tmp,nearst(t,b[i].p[j],b[i].p[j+1]));
ans=max(ans,tmp.dis); return tmp.p;
}
int main(){
scanf("%d%d",&m,&n); int i;
for (i=1; i<=n; i++) scanf("%lf%lf",&a[i].x,&a[i].y);
for (i=1; i<=m; i++) b[i].init();
int head=0,tail=0;
for (i=1; i<n; i++){
h[++tail].p1=a[i]; h[tail].p2=a[i+1];
updata(a[i]);
}
updata(a[n]);
while (head!=tail){
head=head%M+1;
point l=h[head].p1,r=h[head].p2,u=updata(l),v=updata(r),mid;
while (dist(l,r)>eps){
mid.x=(l.x+r.x)/2; mid.y=(l.y+r.y)/2;
if (dist(mid,u)<dist(mid,v)) l=mid; else r=mid;
}
double tmp=dist(l,u); updata(l);
if (tmp>ans+eps){
tail=tail%M+1; h[tail].p1=h[head].p1; h[tail].p2=mid;
tail=tail%M+1; h[tail].p1=mid; h[tail].p2=h[head].p2;
}
}
printf("%.2f\n",ans);
return 0;
}
by lych
2016.3.2