卧薪尝胆,厚积薄发。
BOI2011 2circles
Date: Wed Aug 15 07:15:19 CST 2018 In Category: NoCategory

Description:

有 $N$ 个顶点的凸多边形,求一个最大的半径 $R$ 使得两个半径为 $R$ 的圆能完全的放置在给出的多边形内且无重叠。
$1\le n \le 50000$

Solution:

二分一个值 $mid$ ,把所有凸多边形的边拆开并向里移 $mid$ 的距离,对这些半平面作半平面交,得到一个凸包,再对这个凸包做旋转卡壳,求出凸包后用旋转卡壳求出凸包最远点对判断距离是否大于 $mid$ 。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
struct point
{
double x,y;
point(double x_ = 0.0,double y_ = 0.0){x = x_;y = y_;}
};
inline double dis(point a,point b){return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));}
inline double RotatingCalipers(point p[],int n)
{
register double ans = 0;
register int i,j;
for(i = 2;i <= n;++i)
{
if(dis(p[1],p[i]) > ans)
{
ans = dis(p[1],p[i]);
j = i;
}
}
for(i = 1;i <= n;++i)
{
while(1)
{
if(dis(p[j % n + 1],p[i]) > dis(p[j],p[i]))j = j % n + 1;
else break;
}
ans = max(ans,dis(p[i],p[j]));
}
return ans;
}
int n;
#define MAXN 50010
#define eps 1e-6
point ps[MAXN],p[MAXN];
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,double k){return point(a.x * k,a.y * k);}
inline double dotmul(point a,point b){return a.x * b.x + a.y * b.y;}
inline double crossmul(point a,point b){return a.x * b.y - a.y * b.x;}
inline double angle(point v){return atan2(v.y,v.x);}
inline bool equal(double a,double b){return fabs(a - b) < eps;}
inline int sign(double k){return (equal(k,0.0) ? 0 : (k < 0 ? -1 : 1));}
struct plane
{
point p;point v;
plane(){};
plane(point p_,point v_){p = p_;v = v_;}
}pl[MAXN],q[MAXN];
bool cmp(plane a,plane b){return angle(a.v) < angle(b.v);}
inline bool in(point a,plane b){return sign(crossmul(b.v,(a - b.p))) <= 0;}
inline point intersection(plane a,plane b){return b.p + b.v * (crossmul(a.v,a.p - b.p) / crossmul(a.v,b.v));}
#define F 10000000
#define N -10000000
int head,tail;
inline int HPI(int n)
{
sort(pl + 1,pl + 1 + n,cmp);
register int n0 = 0;
for(register int i = 1;i <= n;++i)
{
if(n0 == 0)pl[++n0] = pl[i];
else if(!equal(angle(pl[n0].v),angle(pl[i].v)))pl[++n0] = pl[i];
else if(!in(pl[n0].p,pl[i]))pl[n0] = pl[i];
}
n = n0;
head = 1;tail = 2;
q[1] = pl[1];q[2] = pl[2];
for(register int i = 3;i <= n;++i)
{
while(head < tail && !in(intersection(q[tail],q[tail - 1]),pl[i]))--tail;
while(head < tail && !in(intersection(q[head],q[head + 1]),pl[i]))++head;
if(head == tail && sign(crossmul(q[head].v,pl[i].v)) <= 0)return -1;
q[++tail] = pl[i];
}
while(head < tail && !in(intersection(q[tail],q[tail - 1]),q[head]))--tail;
register int m = tail - head + 1;
for(register int i = 1;i < m;++i)p[i] = intersection(q[head + i],q[head + i - 1]);
p[m] = intersection(q[head],q[tail]);
return m;
}
double leng(point v){return sqrt(v.x * v.x + v.y * v.y);}
inline void getplane(double len)
{
register plane k;
for(register int i = 2,c = 2,p = 1;i <= n + 1;++i,c = (i - 1) % n + 1,p = i - 1)
{
k = plane(ps[c],ps[p] - ps[c]);
register point s = k.v;
swap(s.y,s.x);s.y = -s.y;
register double l = leng(s);
s = s * (len / l);
k.p = (k.p + s);
pl[i - 1] = k;
}
return;
}
int main()
{
freopen("2circles.in","r",stdin);
freopen("2circles.out","w",stdout);
scanf("%d",&n);
for(register int i = 1;i <= n;++i)
{
scanf("%lf%lf",&ps[i].x,&ps[i].y);
}
register double maxl = RotatingCalipers(ps,n);
register double l = 0.0,r = maxl,mid;
while(r - l > 1e-3)
{
mid = (l + r) / 2;
getplane(mid);
int k = HPI(n);
if(k == -1){r = mid;continue;}
if(RotatingCalipers(p,k) >= mid * 2)l = mid;
else r = mid;
}
printf("%.3lf\n",l);
fclose(stdin);
fclose(stdout);
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡