首页 > 代码库 > 牛吃草_二分法

牛吃草_二分法

Description

农夫有一个长满草的(x0, y0)为圆心,r为半径的圆形牛栏,他要将一头牛栓在坐标(x1, y1)栏桩上,但只让牛吃到一半草,问栓牛鼻的绳子应为多长?

Input

输入一个T,表示T组测试数据
下面T行每行五个整数 x0, y0, x1, y1, r 所有数据的绝对值小于1e5

Output

每组测试数据输出绳子长度,保留4位小数

Sample Input

2
0 0 0 0 2
0 0 10 10 2

Sample Output

1.4142
14.1892

 

 

【思路】

while(rt-lt>eps)二分法,无限逼近

 

#include<iostream>
#include<string.h>
#include<math.h>
#include<stdio.h>
using namespace std;
const double pi=acos(-1.0);
const double eps=1e-8;
double get_s(double mid,int r,int d,double a,double b)//计算面积
{
    return mid*mid*a-mid*mid*sin(a)+r*r*b-r*r*sin(b);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        double x0,y0,x1,y1,r;
        scanf("%lf%lf%lf%lf%lf",&x0,&y0,&x1,&y1,&r);
        double d=sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0));
        double lt=d,rt=sqrt((d*d)+(r*r));

         if(d+r/(sqrt(2))-r<eps)//如果两个圆心重合,则满足所求R=r/sqrt(2);
          {
              printf("%.4f\n",1.0*r/sqrt(2));
              continue;
          }

        double s=pi*r*r;
        double mid=0.0;
        while(rt-lt>eps)//二分
        {
            mid=(lt+rt)/2.0;

            double a=2*acos(((mid*mid)+(d*d)-(r*r))/(2.0*mid*d));//求圆心角a
            double b=2*acos(((d*d)+(r*r)-(mid*mid))/(2.0*d*r));//求圆心角b

            double ss= get_s(mid,r,d,a,b);
            if(ss-s>eps)
                rt=mid-eps;
            else lt=mid+eps;
        }
        printf("%.4f\n",mid);

    }

    return 0;
}

 

牛吃草_二分法