版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/84311672
题目链接:http://poj.org/problem?id=3525
题意:在凸边形内找出一点,使得到多边形边界的距离最大。
题解:
参考博客:https://blog.csdn.net/zuzhiang/article/details/78404556
转化为求多边形内可以放入的最大的圆的半径。二分求解。
///半平面交
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=111;
struct point
{
double x,y;
point(){}
point(double _x,double _y){
x=_x;y=_y;
}
}poly[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 p) { return point(a.x*p,a.y*p);}
point operator / (point a,double p) { return point(a.x/p,a.y/p);}
bool operator < (const point &a,const point &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
if(fabs(x)<esp) return 0;
else return x<0?-1:1;
}
bool operator == (const point &a,const point &b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Cross(point P,point Q)
{
return P.x*Q.y-P.y*Q.x;
}
double Length(point A) { return sqrt(A.x*A.x+A.y*A.y);}
struct LINE
{
point s,t;
double angle;
LINE(){}
LINE(point _s,point _t){
s=_s;t=_t;
angle=atan2(t.y-s.y,t.x-s.x);
}
}L[maxn],dq[maxn],trans[maxn];///存储向量,半平面交时用到的双端队列dq
point Getlinenode(LINE a,LINE b)
{
point P=a.s,v=a.t-a.s; ///点,向量
point Q=b.s,w=b.t-b.s;
point u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
bool cmp(LINE P,LINE Q) ///两向量方向相同,靠下的优先
{
if(fabs(P.angle-Q.angle)<esp)
return Cross(P.s-P.t,Q.s-P.t)>esp;
return P.angle<Q.angle;
}
bool Onright(LINE L,point p){ ///判断点p在直线L的右边,
return Cross(L.s-L.t,p-L.t)>esp;
}
int Half(int n,int &m)
{
sort(L,L+n,cmp);
int l=0,r=1;
m=1;
for(int i=1;i<n;++i)///筛掉同斜率,保留靠下的向量,其余不要
if(fabs(L[i].angle-L[i-1].angle)>esp)L[m++]=L[i];
n=m;
m=0;
dq[0]=L[0],dq[1]=L[1];
for(int i=2;i<n;++i)
{
if(dcmp(Cross(dq[r].s-dq[r].t,dq[r-1].s-dq[r-1].t))==0||dcmp(Cross(dq[l].s-dq[l].t,dq[l+1].s-dq[l+1].t))==0) return;
///交点在直线的右边,舍去
while(l<r&&Onright(L[i],Getlinenode(dq[r],dq[r-1]))>0)--r;
while(l<r&&Onright(L[i],Getlinenode(dq[l],dq[l+1]))>0)++l;
dq[++r]=L[i];
}
///判断下头尾向量
while(l<r&&Onright(dq[l],Getlinenode(dq[r],dq[r-1]))>0)--r;
while(l<r&&Onright(dq[r],Getlinenode(dq[l],dq[l+1]))>0)++l;
if(r-l<=1) return 0;
return 1;
// dq[++r]=dq[l];///将头向量加到尾部
// for(int i=l;i<r;++i)
// poly[m++]=Getlinenode(dq[i],dq[i+1]);///存储m+1个(范围在[0,m])半平面交点
}
void Change(int n,double h) ///将所有边往内缩进h距离
{
double dx,dy,len;
for(int i=0;i<n;i++)
{
len=Length(trans[i].s-trans[i].t);
dx=(trans[i].s.y-trans[i].t.y)/len*h;
dy=(trans[i].t.x-trans[i].s.x)/len*h;
L[i].s.x=trans[i].s.x+dx;
L[i].s.y=trans[i].s.y+dy;
L[i].t.x=trans[i].t.x+dx;
L[i].t.y=trans[i].t.y+dy;
L[i].angle=trans[i].angle;
}
}
double BSearch(int n) ///二分搜索
{
double l=0,r=20000,mid;
int m;
while(l+esp<r)
{
mid=(l+r)/2.0;
Change(n,mid);
if(Half(n,m)) l=mid;
else r=mid;
}
return l;
}
int main()
{
int n,m,t;
while(scanf("%d",&n)&&n)
{
for(int i=0;i<n;++i)
scanf("%lf%lf",&poly[i].x,&poly[i].y);
poly[n]=poly[0];
for(int i=0;i<n;++i)
{
trans[i]=LINE(poly[i],poly[i+1]);
}
printf("%.6f\n",BSearch(n));
}
return 0;
}