《算法笔记》二分—木棒切割问题&求凸多边形外接圆最大半径

木棒切割问题

大意:给N根木棒,通过切割至少得到K段长度相同的木棒,长度相同的木棒最长能有多长
思路:已知结论,长度相同的木棒长度越长,切割得到的K越小,可以二分法,即求最后一个满足“k<=K”的L,可转换为第一个满足“k>K”的位置,再减一

#include<stdio.h>
#include<algorithm>
using namespace std;

int main()
{
    int n,K,k=0,length[10];
    scanf("%d%d",&n,&K);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&length[i]);
    }
    sort(length,length+n);
    int left=1,right=length[n-1],mid;
    while(left<right)
    {
        k=0;
        mid=(left+right)/2;
        for(int i=0;i<n;i++)
        {
            k+=length[i]/mid;
        }
        if(k<K) right=mid;
        else left=mid+1;
    }
    printf("%d",mid-1);
    return 0;
}

二分法求凸多边形外接圆最大半径

大意:给定N条线段,按任意顺序首尾相连,组合成一个凸多边形,使得其外接圆半径最大,求最大半径
思路:首先判断外接圆圆心在多边形内或外或在多边形上。
1.多边形的外接圆的圆心在多边形上或内,所有线段对应的圆心角sum_angle之和为2pi。
将外接圆半径和圆心角之和的关系进行二分
sum_angle<2pi,说明当前半径r需要减小
sum_angle>2pi,说明当前半径r需要增大
2.多边形的外接圆院系在多边形之外,最长线段所对应的圆心角一定为其他角之和
判断条件:其他角之和(other_angle)+2pi-最大角(max_angle)
如果小于2pi,说明半径r需要增大
如果大于2pi,说明半径r需要减小
二分边界:left=最大边长\2(斜边大于直角边),right=10000000

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;

const int maxn =10010;
const double pi=acos(-1.0);
const double eps=1e-5;

double sum_angle(int length[],int n,double R)
{
    double ans=0;
    for(int i=0;i<n;i++)
    {
        ans+=2*asin(length[i]/2/R);
    }
    return ans;
}

double radis(int length[],int n)
{
    double sum,max_angle,other_angle;
    double left,right,mid;
    left=1.0*length[n-1]/2;
    right=1000000;
    sum=sum_angle(length,n,1.0*length[n-1]/2);
    if(fabs(sum-pi*2)<eps)//圆心在最长边上
        return length[n-1]/2;
    while(right-left>eps)
    {
        mid=(left+right)/2;
        if(other_angle<pi)//圆心在外部
        {
            other_angle=sum_angle(length,n-1,mid);
            if(fabs(other_angle+2*pi-max_angle)<eps)
                return mid;
            else if(other_angle+2*pi-max_angle<2*pi)
                left=mid;
            else right=mid;
        }
        else//圆心在内部
        {
            sum=sum_angle(length,n,mid);
            if(fabs(sum-2*pi)<eps)
                return mid;
            else if(sum>2*pi)
                left=mid;
            else
                right=mid;
        }
    }
    return mid;
}

int main()
{
    int n,length[maxn];//边数
    double r;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&length[i]);
    }
    sort(length,length+n);//将边数排序
    r=radis(length,n);
    printf("%.2f\n",r);
    return 0;
}

有错误请之处

posted @ 2021-02-04 21:54  inss!w!  阅读(384)  评论(3编辑  收藏  举报