SGU 332 Largest Circle(凸包内接圆半径nlogn)

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=332

题意:逆时针给出一个凸包,给凸包的最大内接圆半径。

思路:nlogn的算法:

(1)二分内切圆半径的值R

(2)把每个半平面向内平移R的长度

(3)使用一个双端队列(deque),依次向首部加入hplane[0],hplane[1],

     for(i=2;i<num_hplane;i++)

     {

              while(deque顶端的两个半平面的交点在hplane[i]外)  删除deque顶端

              while(deque底部的两个半平面的交点在hplane[i]外)  删除deque底部

              将hplane[i]加入deque顶端

     }

     while(deque顶端的两个半平面的交点在底部半平面外) 删除deque顶端

     while(deque底部的两个半平面的交点在顶端半平面外) 删除deque底部

     判断最后剩下的半平面是否在3个以上

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <map>


#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>=0?(x):-(x))
#define i64 long long
#define u32 unsigned int
#define u64 unsigned long long
#define clr(x,y) memset(x,y,sizeof(x))
#define CLR(x) x.clear()
#define ph(x) push(x)
#define pb(x) push_back(x)
#define Len(x) x.length()
#define SZ(x) x.size()
#define PI acos(-1.0)
#define sqr(x) ((x)*(x))
#define MP(x,y) make_pair(x,y)
#define EPS 1e-5

#define FOR0(i,x) for(i=0;i<x;i++)
#define FOR1(i,x) for(i=1;i<=x;i++)
#define FOR(i,a,b) for(i=a;i<=b;i++)
#define DOW0(i,x) for(i=x;i>=0;i--)
#define DOW1(i,x) for(i=x;i>=1;i--)
#define DOW(i,a,b) for(i=a;i>=b;i--)
using namespace std;


void RD(int &x){scanf("%d",&x);}
void RD(i64 &x){scanf("%I64d",&x);}
void RD(u32 &x){scanf("%u",&x);}
void RD(double &x){scanf("%lf",&x);}
void RD(int &x,int &y){scanf("%d%d",&x,&y);}
void RD(i64 &x,i64 &y){scanf("%I64d%I64d",&x,&y);}
void RD(u32 &x,u32 &y){scanf("%u%u",&x,&y);}
void RD(double &x,double &y){scanf("%lf%lf",&x,&y);}
void RD(int &x,int &y,int &z){scanf("%d%d%d",&x,&y,&z);}
void RD(i64 &x,i64 &y,i64 &z){scanf("%I64d%I64d%I64d",&x,&y,&z);}
void RD(u32 &x,u32 &y,u32 &z){scanf("%u%u%u",&x,&y,&z);}
void RD(double &x,double &y,double &z){scanf("%lf%lf%lf",&x,&y,&z);}
void RD(char &x){x=getchar();}
void RD(char *s){scanf("%s",s);}
void RD(string &s){cin>>s;}


void PR(int x) {printf("%d\n",x);}
void PR(i64 x) {printf("%I64d\n",x);}
void PR(u32 x) {printf("%u\n",x);}
void PR(double x) {printf("%.6lf\n",x);}
void PR(char x) {printf("%c\n",x);}
void PR(char *x) {printf("%s\n",x);}
void PR(string x) {cout<<x<<endl;}

const int N=10005;

int DB(double x)
{
    if(x>EPS) return 1;
    if(x<-EPS) return -1;
    return 0;
}

class point
{
public:
    double x,y;

    point(){}
    point(double _x,double _y)
    {
        x=_x;
        y=_y;
    }

    point operator+(point a)
    {
        return point(x+a.x,y+a.y);
    }

    point operator-(point a)
    {
        return point(x-a.x,y-a.y);
    }

    double operator*(point a)
    {
        return x*a.y-y*a.x;
    }

    point operator*(double t)
    {
        return point(x*t,y*t);
    }

    double operator^(point a)
    {
        return x*a.x+y*a.y;
    }

    point operator/(double t)
    {
        return point(x/t,y/t);
    }

    double getLen()
    {
        return sqrt(x*x+y*y);
    }

    void get()
    {
        RD(x,y);
    }

    int operator==(point a)
    {
        return DB(x-a.x)==0&&DB(y-a.y)==0;
    }

    int operator<(point a)
    {
        if(DB(x-a.x)) return x<a.x;
        return y<a.y;
    }

    point adjust(double L)
    {
        double temp=getLen();
        return point(x*L/temp,y*L/temp);
    }

    void print()
    {
        printf("%.6lf %.6lf\n",x,y);
    }
};


class Vector
{
public:
    point s,t;
    double ang;

    Vector(){}
    Vector(point _s,point _t)
    {
        s=_s;
        t=_t;
        ang=atan2(t.y-s.y,t.x-s.x);
    }

};

Vector a[N],b[N],st[N];
point p[N];
int n;


double cross(point a,point b,point p)
{
    return (b-a)*(p-a);
}

int in(point p,Vector a)
{
    return cross(a.s,a.t,p)>0;
}

point getCross(Vector a,Vector b)
{
    double s1=(a.s-b.s)*(a.t-b.s);
    double s2=(a.t-b.t)*(a.s-b.t);
    return (b.s*s2+b.t*s1)/(s1+s2);
}


Vector move(Vector a,double L)
{
    point d=point(a.s.y-a.t.y,a.t.x-a.s.x);
    d=d.adjust(L);
    return Vector(a.s+d,a.t+d);
}

int cmp(Vector a,Vector b)
{
    return a.ang<b.ang;
}


int OK(double L)
{
    int i;
    FOR1(i,n) b[i]=move(a[i],L);
    int head=1,tail=1;
    st[1]=b[1];
    for(i=2;i<=n;i++)
    {
        while(tail>head&&!in(getCross(st[tail-1],st[tail]),b[i])) tail--;
        while(tail>head&&!in(getCross(st[head],st[head+1]),b[i])) head++;
        st[++tail]=b[i];
    }
    while(tail>head&&!in(getCross(st[tail],st[tail-1]),st[head])) tail--;
    while(tail>head&&!in(getCross(st[head],st[head+1]),st[tail])) head++;
    return tail>head+1;
}


int main()
{
    RD(n);
    int i;
    FOR1(i,n) p[i].get();
    p[0]=p[n];
    FOR1(i,n) a[i]=Vector(p[i-1],p[i]);
    double low=0,high=1e8,mid;
    while(DB(low-high)==-1)
    {
        mid=(low+high)/2;
        if(OK(mid)) low=mid;
        else high=mid;
    }
    PR(mid);
    return 0;
}

  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值