[计算几何]离大海的最远点在哪里

针对凸多边形寻找一点,使其到各边的最短距离最大化。采用二分法逼近答案,通过堆和双向链表维护边的相对位置,实现高效计算。

题意:给定一个凸多边形,求一个点使得它到各条边的距离的最小值最大。

这本来是一道poj原题,n<=100,但是貌似精度有问题,poj死都过不去,以后再试试...

这次做的是一道改编题,n<=200000,一组数据。

显然可以二分答案,并且把边往里面推,但是这样的话常数太大过不了..

但是我们发现,一条边消失是在距离超过 它和相邻的边的角平分线的交点到它的距离 的时候。所以我们可以用一个堆来模拟推进,用双向链表维护相邻的边。

然后作为一个计算几何菜鸡,我做完感觉意识模糊...

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#define eps 1e-9
#define ld long double
#define MAXN 200000
#define pa pair<ld,int> 
#define mp(x,y) make_pair(x,y)
using namespace std;
//********************
struct P{
    ld x,y;
    P(ld _x=0,ld _y=0):x(_x),y(_y){}
}s[MAXN+5];
struct L{P u,v;}l[MAXN+5];
P operator+(P x,P y){return P(x.x+y.x,x.y+y.y);}
P operator-(P x,P y){return P(x.x-y.x,x.y-y.y);}
ld operator*(P x,P y){return x.x*y.y-y.x*x.y;}
P operator/(P x,ld y){return P(x.x/y,x.y/y);}
P operator*(P x,ld y){return P(x.x*y,x.y*y);}
ld dot(P x,P y){return x.x*y.x+x.y*y.y;}
ld dis(P x){return sqrt(x.x*x.x+x.y*x.y);}
P operator*(L a,L b){return a.u+a.v*(b.v*(a.u-b.u)/(a.v*b.v));}
//********************
int n,ne[MAXN+5],la[MAXN+5];
priority_queue<pa > q;
bool mark[MAXN+5];
 
L solve(L a,L b){return (L){a*b,a.v*dis(b.v)-b.v*dis(a.v)};}
 
ld calc(int x)
{
    P p=solve(l[la[x]],l[x])*solve(l[x],l[ne[x]]);
    //cout<<"calc"<<x<<" "<<-fabs(p*l[x].v/dis(l[x].v))<<endl;
    return -fabs((l[x].v*(p-l[x].u))/dis(l[x].v));
}
 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%Lf%Lf",&s[i].x,&s[i].y);
    for(int i=1;i<=n;i++)ne[i-1]=i,la[i]=i-1;
    la[1]=n,ne[n]=1;
    for(int i=1;i<=n;i++)l[i]=(L){s[i],s[i]-s[la[i]]};
    for(int i=1;i<=n;i++)q.push(mp(calc(i),i));
    for(int i=2;i<n;i++)
    {
        while(!q.empty()&&mark[q.top().second])q.pop();
        int x=q.top().second;mark[x]=1;
        la[ne[x]]=la[x];ne[la[x]]=ne[x];
        q.push(mp(calc(la[x]),la[x]));
        q.push(mp(calc(ne[x]),ne[x]));
    }
    printf("%0.8Lf",-q.top().first);
    return 0;
}

 

转载于:https://www.cnblogs.com/FallDream/p/fzoj1630.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值