算法笔记4.5.2二分扩展:凸多边形的外接圆之最大半径

算法笔记4.5.2二分扩展:凸多边形的外接圆之最大半径

二分法求外接圆最大半径

题目描述

给出N个线段长度,试将它们头尾相接组合成一个凸多边形,使凸多边形的外接圆(多边形每个顶点都在圆上)的半径最大,求该最大半径。其中N<=10^5,线段长度均不超过100,要求算法中不涉及坐标的计算。

思路:

二分算法的本质就是通过不断迭代使left 和 right 在固定条件下逐渐靠近真实值,符合一定误差,所以实际上把该题放在二分扩展里面,这个所谓的最大半径的“最大”是不在求解中的,最大应该算题干,先组成一个有外接圆的凸多边形,然后求其半径即可。不要误入歧途在“最大”上绞尽脑汁。
  外接圆圆心与每个线段顶点连接后会有一个圆心角,如果圆心在凸多边形内部,则所有圆心角之和应该为2π。如果圆心在凸多边形外部,则最大的圆心角等于其他圆心角之和。
  因此设定初值,求出每个线段对应的圆心角,使所有圆心角之和等于2π。不断迭代逼近真值即可。当所求圆心角大于2π时,增大r尝试,小于2π时,缩小r尝试。
  当圆心在多边形外面时,取圆心角之和为其他圆心角+2π-最大圆心角,同时逼近的方向与前面相反。
  半径应该大于等于最大边的一半。其中等于的情况单独处理。

代码如下

  #include<cstdio>
 #include<cmath>
 const double PI=acos(-1.0);
 const double eps=1e-5;//比较精度
  //求圆心角之和
double totalCornerAngles(double edges[],int n,double r)
{
    double sum = 0.0;
    for(int i =0;i<n;i++)
        sum+=asin(edges[i]/2/r)*2;
    return sum;
}
//二分法求半径

int main()
{

    int N;//边数
    scanf("%d",&N);//输入边数
    double edges[N];//边长数组

    double sum;//圆心角之和
    double maxAngle=0.0;//最长边对应的圆心角
    double maxEdge=0.0;//最长边


    //初始化edges
    for(int i=0;i<N;i++)
    {
        scanf("%lf",&edges[i]);
        if(edges[i]>maxEdge)
            maxEdge = edges[i];//保存最大边
    }
    //以最长边为直径求圆心角之和,若为2π则直接返回
    sum = totalCornerAngles(edges,N,maxEdge/2);
    if(fabs(sum-PI*2)<eps)
    {
        printf("外接圆的最大半径是最大边的一半:%.2f",maxEdge/2);
        return 0 ;
    }

    //半径大于最大边的一半(即斜边大于直角边)
    double left =maxEdge/2,right=10000000,mid;
    double other=0;

     //在误差范围内循环求解
    while(right -left >eps)
    {
         mid = (right + left) /2;
         maxAngle=asin(maxEdge/2/mid)*2;//求出最大边对应的圆心角
         sum = totalCornerAngles(edges,N,mid);
         other=sum-maxAngle;
         //如果除去最大圆心角的其他圆心角之和小于π,说明圆心在多边形外面
         if(other<PI)
         {
             sum=other+2*PI-maxAngle;
             if( sum<2*PI)
                 left = mid;
             else
                 right = mid;
         }
         //圆心在多边形里面
         else
         {
             if( sum>2*PI)
                 left = mid;
             else
                right = mid;
         }
    }
    printf("外接圆的最大半径是:%.2f",mid);
    return 0;
 }

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值