sgu 332 Largest Circle 求凸n边形内最大圆半径

题目链接


题意:

求凸n边形内最大圆半径


解法:

二分圆半径即可,之后对于n边形的每条边,向内推动当前mid距离,进行半平面交,如果有解,证明存在符合条件的半径。


代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iomanip>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s)  memset(a,x,(s)*sizeof a[0])
#define mem(a,x)  memset(a,x,sizeof a)
#define ysk(x)  (1<<(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn=  10000  ;

const double PI=acos(-1.0);
const double eps=1e-10;
const double eps2=1e-5;
int dcmp(double x)
{
    if(fabs(x)<eps)  return 0;
    else return x<0?-1:1;
}
struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) {};
    bool operator ==(const Point B)const {return dcmp(x-B.x)==0&&dcmp(y-B.y)==0;}

    bool operator<(const Point& b)const
    {
        return dcmp(x-b.x)<0|| dcmp(x-b.x)==0 &&dcmp(y-b.y)<0;
    }
};
typedef Point Vector;
Vector operator -(Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y); }


double Cross(Vector A,Vector B)//叉乘
{
    return A.x*B.y-A.y*B.x;
}

double Dot(Vector A,Vector B)//点乘
{
    return A.x*B.x+A.y*B.y;
}

Vector operator +(Vector A,Vector B) {return Vector(A.x+B.x,A.y+B.y); }
Vector operator *(Vector A,double p) {return Vector(A.x*p,A.y*p); }
Vector operator /(Vector A,double p) {return Vector(A.x/p,A.y/p); }
Vector operator -(Vector A)  {return  Vector(-A.x,-A.y);}

double Length(Vector A)
{
    return sqrt(Dot(A,A));
}

struct Line
{
    Point p,p2;
    Vector v;
    double ang;
    Line(){}
    Line(Point a,Vector v):p(a),v(v){ang=atan2(v.y,v.x); }//点线式
    void twoPointIntial(Point p,Point p2)//两点式
    {
        this->p=p;
        this->p2=p2;
        v=  p2-p;
        ang=atan2(v.y,v.x);
    }
    Point point(double t)//参数方程求参数t对应点
    {
        return p+v*t;
    }
    bool operator<(const Line & L)const
    {
        return ang<L.ang;
    }
};

Point GetIntersection(Line a,Line b)
{
    Vector u=a.p-b.p;
    double t=Cross(b.v,u)/Cross(a.v,b.v);
    return a.p+a.v*t;
}

bool OnRight(Line L,Point p)
{
    return dcmp(Cross(L.v,p-L.p))<0;
}
Point p[maxn+10];
Line q[maxn+10];
int HalfplaneIntersection(Line* L,int n)
{
    sort(L,L+n);
    int first,last;
    q[first=last=0]=L[0];
    for(int i=1;i<n;i++)
    {
        while(first<last&&OnRight(L[i],p[last-1] ) )  last--;
        while(first<last&&OnRight(L[i],p[first]))  first++;
        q[++last]=L[i];
        if(fabs(Cross(q[last].v,q[last-1].v) )<eps )
        {
            last--;
            if(!OnRight(q[last],L[i].p) )  q[last]=L[i];
        }
        if(first<last) p[last-1]=GetIntersection(q[last-1],q[last] );
    }
    while(first<last&&OnRight(q[first],p[last-1])) last--;
    if(last-first<=1)  return 0;//小于3个,不存在
    p[last]=GetIntersection(q[last],q[first]);
    return last-first+1;


}
Point po[maxn+10];
Line L[maxn+10];
int np;
double bs(double le,double ri)
{
    double x[2],y[2];
    while(le+eps2<ri)
    {
        double mid=(le+ri)/2;
        for0(i,np)
        {
            Vector v=po[(i+1)%np]-po[i];
            double len=Length(v);
            double deltax=mid*v.y/len;
            double deltay=mid*v.x/len;
            x[0]=po[i].x- deltax ;
            y[0]=po[i].y+ deltay ;

            x[1]=po[(i+1)%np ].x- deltax ;
            y[1]=po[(i+1)%np ].y+ deltay  ;


            Point S(x[0],y[0]),E(x[1],y[1]);
            L[i].twoPointIntial(S,E);
        }
        if(!HalfplaneIntersection(L,np))  ri=mid;
        else le=mid;
    }
    return ri;
}
int main()
{
   std::ios::sync_with_stdio(false);
   while(cin>>np)
   {
      for0(i,np)  cin>>po[i].x>>po[i].y;
      cout<<fixed<<setprecision(6)<<bs(0,1e7)<<endl;
   }
   return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值