Most Distant Point from the Sea POJ - 3525 

题意: 求点到多边形的最远距离

思路: 用半平面交,求凸多边形的最大内切圆半径,二分r

#include<cstdio>
#include<vector>
#include<cmath>
#include<string>
#include<string.h>
#include<iostream>
#include<algorithm>
#define PI acos(-1.0)
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e3+3;
const int MOD=1e9+7;
template <class T>
bool sf(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
int sign(double x) {  //三态函数,减少精度问题
    return abs(x) < 1e-10 ? 0 : x < 0 ? -1 : 1;
}
struct Point { //点的定义
    double x, y;
    Point(double x=0.0, double y=0.0) : x(x), y(y) {}
    Point operator + (const Point &rhs) const {  //向量加法
        return Point(x + rhs.x, y + rhs.y);
    }
    Point operator - (const Point &rhs) const {  //向量减法
        return Point(x - rhs.x, y - rhs.y);
    }
    Point operator * (double p) const {  //向量乘以标量
        return Point(x * p, y * p);
    }
    Point operator / (double p) const {  //向量除以标量
        return Point(x / p, y / p);
    }
    bool operator < (const Point &rhs) const {  //点的坐标排序
        return x < rhs.x || (x == rhs.x && y < rhs.y);
    }
    bool operator == (const Point &rhs) const {  //判断同一个点
        return sign(x - rhs.x) == 0 && sign(y - rhs.y) == 0;
    }

};
typedef Point Vector;
double polar_angle(Vector A) {  //向量极角
    return atan2(A.y, A.x);
}

struct Line {  //有向直线的定义,左边就是对应的半平面
    Point p,s;  //直线上任意一点
    Vector v;  //方向向量
    double ang;  //极角,即从x正方向旋转到向量v所需的角(弧度)
    Line() {}
    Line(Point p, Point s, Vector v) : p(p), s(s) ,v(v) {
        ang = polar_angle(v);
    }
    bool operator < (const Line &rhs) const {
        return ang < rhs.ang;
    }
    Point point(double a) {
        return p + v * a;
    }
};
double cross(Vector A, Vector B) {  //向量叉积,两向量组成的三角形的有向面积的两倍,可判断两向量的方向
    return A.x * B.y - A.y * B.x;
}
bool point_on_left(Point p, Line L) {  //判断点在直线左侧
    return cross(L.v, p-L.p) > 0;
}
Point line_line_inter(Point p, Vector V, Point q, Vector W) {  //两直线交点,参数方程
    Vector U = p - q;
    double t = cross(W, U) / cross(V, W);  //两直线有唯一交点的前提:cross(V, W)非0
    return p + V * t;
}
Point p[N];
Line Q[N];
typedef vector<Point> polygon;
typedef vector<Point> polygon;

bool HPIcmp(Line a,Line b){
	if(fabs(a.ang - b.ang) > 1e-7)return a.ang < b.ang; //斜率排序
	//斜率相同
	return sign(cross((a.p - b.p),(b.s - b.p))) < 0;
}
polygon half_plane_inter(vector<Line> line){
    int n=(int)line.size();
    int tot=n;
    sort(line.begin(),line.end(),HPIcmp);
    polygon ans;
    tot = 1;
	for(int i = 1;i < n;i++)
		if(fabs(line[i].ang - line[i-1].ang) > 1e-7) //去掉斜率重复的
			line[tot++] = line[i];
	int head = 0, tail = 1;
	Q[0] = line[0];
	Q[1] = line[1];
	for(int i = 2; i < tot; i++){ //如果双端队列底端或顶端两个半平面的交点在当前半平面之外,则删除
		if(fabs(cross((Q[tail].s-Q[tail].p),(Q[tail-1].s-Q[tail-1].p))) <1e-7 ||
		fabs(cross((Q[head].s-Q[head].p),(Q[head+1].s-Q[head+1].p))) <1e-7)
			return ans;
		while(head < tail && sign(cross(line_line_inter(Q[tail].p,Q[tail].v,Q[tail-1].p,Q[tail-1].v)-line[i].p,line[i].s-line[i].p))>0)
			tail--;
		while(head < tail && sign(cross(line_line_inter(Q[head].p,Q[head].v,Q[head+1].p,Q[head+1].v)-line[i].p,line[i].s-line[i].p))>0)
			head++;
		Q[++tail] = line[i];
	}
	while(head < tail && sign(cross(line_line_inter(Q[tail].p,Q[tail].v,Q[tail-1].p,Q[tail-1].v)-Q[head].p,Q[head].s-Q[head].p))>0)
		tail--;
	if(tail <= head + 1) return ans;
	//保存点到ans
	for(int i = head; i < tail; i++)
		ans.pb(line_line_inter(Q[i].p,Q[i].v,Q[i+1].p,Q[i+1].v));
	if(head < tail - 1)
		ans.pb(line_line_inter(Q[head].p,Q[head].v,Q[tail].p,Q[tail].v));
    return ans;
}
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) {  //向量的单位法向量,确保A不是零向量
    double len = length(A);
    return Vector(-A.y/len, A.x/len);
}
Vector V1[N];
int main(void){
    int T,n;
    while(cin>>n){
        if(!n)  break;
        for(int i=0;i<n;i++)    scanf("%lf%lf",&p[i].x,&p[i].y);
//        reverse(p,p+n);
        for(int i=0;i<n;i++){
            Line t;
            t={p[i],p[(i+1)%n],p[(i+1)%n]-p[i]};
            V1[i]=normal(p[(i+1)%n]-p[i]);
        }
        double l=0,r=20000;
        for(int i=1;i<=50;++i){
            vector<Line> L;
            double mid=(l+r)/2.0;
            for(int i=0;i<n;i++){
                Line q( (p[i]+V1[i]*mid),(p[(i+1)%n]+V1[i]*mid),p[(i+1)%n]-p[i] );
                L.pb(q);
            }
            vector<Point> res=half_plane_inter(L);

            if((int)res.size()>0)   l=mid;
            else    r=mid;
        }
        printf("%.10f\n",r);

    }

    return 0;
}