《算法笔记》二分—木棒切割问题&求凸多边形外接圆最大半径
木棒切割问题
大意:给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;
}
有错误请之处