POJ3525 Most Distant Point from the Sea(半平面交)

有一个海岛,求海岛上距离海岸线最远的点。lrj白皮书例题,我这里也有介绍半平面交的相关知识。直接求不好求,于是二分这个距离,把海岸线向”里”(逆时针给出边的时候左边为里,也就是它对应的半平面)移动这个距离,如果这些半平面有交集,则说明距离不够远,如果没有交集则说明距离太远。于是二分到恰好没有交集。

#include<cstdio>
#include<cmath>
#include<algorithm>
#define MAXN 110
using namespace std;
struct poi
{
    double x,y;
    poi(double x = 0,double y = 0) :x(x),y(y) {}
}pos[MAXN],a[MAXN],out[MAXN],v1[MAXN],v2[MAXN];
typedef poi vec;
vec operator +(vec A,vec B) {return vec(A.x+B.x, A.y+B.y);}
vec operator -(vec A,vec B) {return vec(A.x-B.x, A.y-B.y);}
vec operator *(vec A,double p) {return vec(A.x*p, A.y*p);}
const double eps = 1e-7;
int dcmp(double x)
{
    if(fabs(x) < eps) return 0;
    else return x>0?1:-1;
}
bool operator <(vec A, vec B)
{
    if(A.x == B.x) return A.y < B.y;
    else return A.x < B.x;
}
double cross(vec A,vec B) {return A.x*B.y - A.y*B.x;}
double dot(vec A,vec B) {return A.x*B.x + A.y*B.y;}
double length(vec A) {return sqrt(dot(A,A));}
vec normal(vec A) {double L = length(A); return vec(-A.y/L, A.x/L);}
struct Line
{
    poi p; vec v;
    double ang;
    Line(){}
    Line(poi p,vec v) :p(p),v(v) {ang = atan2(v.y,v.x);} 
    bool operator <(const Line &b)const{return ang < b.ang;}
}L[MAXN],Q[MAXN];
bool Onleft(Line A,poi p) {return cross(A.v, p-A.p) > 0;}
poi GetLineIntersection(Line A,Line B)
{
    double t = cross(B.v, A.p-B.p) /cross(A.v, B.v);
    return A.p + A.v*t;
}
int HalfplaneIntersection(int n)
{
    sort(L,L+n);
    int head = 0,tail = 0;
    Q[0] = L[0];
    for(int i = 0; i < n; i++)
    {
        while(head < tail&& !Onleft(L[i], a[tail-1])) --tail;
        while(head < tail&& !Onleft(L[i], a[head])) ++head;
        Q[++tail] = L[i];
        if(fabs(cross(Q[tail].v,Q[tail-1].v)) < eps){
            tail--;
            if(Onleft(Q[tail], L[i].p)) Q[tail] = L[i];
        }
        if(head < tail) a[tail-1] = GetLineIntersection(Q[tail], Q[tail-1]);
    }
    while(head < tail&& !Onleft(Q[head], a[tail-1])) --tail;
    if(tail - head <= 1) return 0;
    a[tail] = GetLineIntersection(Q[head], Q[tail]);

    int m = 0;
    for(int i = head; i <= tail; i++) out[m++] = a[i];
    return m;
}
int main()
{
    int n;
    while(scanf("%d",&n) != EOF&&n)
    {
        for(int i = 0; i < n; i++) scanf("%lf%lf",&pos[i].x,&pos[i].y);
        for(int i = 0; i < n; i++)
        {
            v1[i] = pos[(i+1)%n] - pos[i];
            v2[i] = normal(v1[i]);
        }
        double l = 0, r = 20000, mid;
        while(r-l > eps)
        {
            mid = (l+r)/2;
            for(int i = 0; i < n; i++) L[i] = Line(pos[i] + v2[i]*mid, v1[i]);
            int m = HalfplaneIntersection(n);
            if(!m) r = mid; else l = mid;
        }
        printf("%.6lf\n",l);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值