题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1891
思路:
1.求一点到凸包边界最远,即求最大内切圆半径。
2.二分半径r,讲凸包上边像内平移(点p+(normal vector)*r,方向向量v),求半平面交。若交点大于0,此时半径仍可扩大(即所求圆并未与边相切)。若交点等于0,则此时可能存在一内切圆,继续缩小半径。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug
using namespace std;
const double eps=1e-6;
const double PI=acos(-1.0);
const int maxn=200;
struct Point
{
double x,y;
Point() {}
Point(double x,double y):x(x),y(y) {}
void read()
{
scanf("%lf%lf",&x,&y);
}
};
typedef Point Vector;
Vector operator - (Vector A,Vector B)
{
return Vector(A.x-B.x,A.y-B.y);
}
Vector operator + (Vector A,Vector B)
{
return Vector(A.x+B.x,A.y+B.y);
}
Vector operator * (Vector A,double t)
{
return Vector(A.x*t,A.y*t);
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
double Dot(Vector A,Vector B)
{
return A.x*B.x+A.y*B.y;
}
double Length(Vector A)
{
return sqrt(Dot(A,A));
}
Vector Normal(Vector A)
{
double L=Length(A);
return Vector(-A.y/L,A.x/L);
}
struct Line
{
Point P;
Vector v;
double ang;
Line() {}
Line(Point p,Vector v):P(p),v(v)
{
ang=atan2(v.y,v.x);
}
bool operator < (const Line& L) const
{
return ang<L.ang;
}
Line Move(double d)
{
Vector tmp=Normal(v);
return Line(P+tmp*d,v);
}
};
bool onLeft(Line L,Point p)
{
return Cross(L.v,p-L.P)>0;
}
Point getIntersection(Line a,Line b)
{
Vector u=a.P-b.P;
double t=Cross(b.v,u)/Cross(a.v,b.v);
return a.P+a.v*t;
}
int Half_Plane_Intersection(Line* L,int n,Point* poly)
{
sort(L,L+n);
int first,last;
Point* p=new Point[n];
Line* q=new Line[n];
q[first=last=0]=L[0];
for(int i=1; i<n; i++)
{
while(first<last&&!onLeft(L[i],p[last-1])) last--;
while(first<last&&!onLeft(L[i],p[first])) first++;
q[++last]=L[i];
if(fabs(Cross(q[last].v,q[last-1].v))<eps)
{
last--;
if(onLeft(q[last],L[i].P)) q[last]=L[i];
}
if(first<last) p[last-1]=getIntersection(q[last-1],q[last]);
}
while(first<last&&!onLeft(q[first],p[last-1])) last--;
if(last-first<=1) return 0;
p[last]=getIntersection(q[last],q[first]);
int m=0;
for(int i=first; i<=last; i++)
poly[m++]=p[i];
return m;
}
int n;
Line l[maxn];
Point p[maxn];
int check(double r)
{
for(int i=0; i<n; i++)
{
Vector v=Normal(p[(i+1)%n]-p[i]);
l[i]=Line(p[i],p[(i+1)%n]-p[i]).Move(r);
}
Point poly[maxn];
return Half_Plane_Intersection(l,n,poly)==0;
}
double solve()
{
double L=0,R=20000,ans;
while(dcmp(R-L)!=0)
{
double mid=(L+R)/2;
if(check(mid))
{
ans=mid;
R=mid;
}
else
{
L=mid;
}
}
return ans;
}
int main()
{
#ifdef debu
freopen("in.txt","r",stdin);
#endif // debug
while(scanf("%d",&n)!=EOF&&n)
{
for(int i=0; i<n; i++) p[i].read();
printf("%.6f\n",solve());
}
return 0;
}