HDU 6097 Mindis(圆的反演)

传送门


题意:


有一个圆,圆心是(0,0),半径是r,有两个到圆心距离相等的点分布在圆上或圆内,问在圆上找一点使得这点到那两个点的距离和,输出最小的距离。



思路:

首先题目的规模达到了500000,在3s内跑完,如果用三分的话,精度达到1e-6,一个数据大约找50遍,这样复杂度就爆炸了。
最好的方法是一组数据由一个式子直接得出来,这样复杂度O(1),还可以跑完。


接下来推公式。



代码:

#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
const double eps=1e-8;
typedef pair<double, double>point;

double Dist(const point &P1,const point &P2)
{
    double dx=P1.first-P2.first;
    double dy=P1.second-P2.second;
    return sqrt(dx*dx+dy*dy);
}

int main ()
{
    point P1,P2;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        double R;
        scanf("%lf",&R);
        scanf("%lf %lf",&P1.first,&P1.second);
        scanf("%lf %lf",&P2.first,&P2.second);
        double C=Dist(P1,P2)/2.0;
        double D=Dist(point(0,0),P1);
        if(D<eps)
        {
            printf("%.7f\n",R*2.0);
            continue;
        }
        double d=sqrt(D*D-C*C);
        double a=C*R/D;
        double y=d*(a*a-C*C)/(C*C);
        if(y<R-d)
        {
            printf("%.7f\n",a*2.0);
            continue;
        }
        printf("%.7f\n",sqrt(C*C+(R-d)*(R-d))*2.0);
    }
    return 0;
}

附上三分写的超时的代码(以后哪天突然开窍了说不定就不T了):

#include <math.h>
#include <stdio.h>
#include <iostream>
using namespace std;
const double eps=1e-7;
double r;
double xx1,xx2,yy1,yy2;
template <class T>
inline bool scan_d(T &ret)
{
    char c;
    int sgn;
    if (c = getchar(), c == EOF)
    {
        return 0; //EOF
    }
    while (c != '-' && (c < '0' || c > '9'))
    {
        c = getchar();
    }
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9')
    {
        ret = ret * 10 + (c - '0');
    }
    ret *= sgn;
    return 1;
}

double f1(double x)//关系表达式
{
    double y=sqrt(r*r-x*x);
    double ans=sqrt((x-xx1)*(x-xx1)+(y-yy1)*(y-yy1));
    double ans2=sqrt((x-xx2)*(x-xx2)+(y-yy2)*(y-yy2));
    return ans+ans2;

}
double sanfen1(double l,double r)
{
    int aa=0;
    while(r-l>eps)        //精度自行设定
    {aa++;
         double ll=(2*l+r)/3;
        double rr=(l+2*r)/3;
        double ans1=f1(ll);
        double ans2=f1(rr);
        if(ans1>ans2)            //符号视情况而定
            l=ll;
        else
            r=rr;
    } //cout<<"aa="<<aa<<endl;
    return f1(l);

}

double f2(double x)//关系表达式
{
    double y=-sqrt(r*r-x*x);
    double ans=sqrt((x-xx1)*(x-xx1)+(y-yy1)*(y-yy1));
     double ans2=sqrt((x-xx2)*(x-xx2)+(y-yy2)*(y-yy2));
    return ans+ans2;

}
double sanfen2(double l,double r)
{
    int aa=0;
    while(r-l>eps)        //精度自行设定
    {aa++;
         double ll=(2*l+r)/3;
        double rr=(l+2*r)/3;
        double ans1=f2(ll);
        double ans2=f2(rr);
        if(ans1>ans2)            //符号视情况而定
            l=ll;
        else
            r=rr;
    } //cout<<"aa="<<aa<<endl;
    return f2(l);
}

int main()
{

    int t;

    scan_d(t);
    while(t--)
    {
        scan_d(r);
        scan_d(xx1);
        scan_d(yy1);
        scan_d(xx2);
        scan_d(yy2);

        double ans=0;
        if(xx1*xx1+yy1*yy1==r*r)
        {
            ans=sqrt((xx2-xx1)*(xx2-xx1)+(yy2-yy1)*(yy2-yy1));
        }
        else if(xx1==-xx2&&yy1==-yy2)
            ans=2*r;
        else if(yy1>=0&&yy2>=0)
            ans=sanfen1(-r,r);
            else if(yy1<0&&yy2<0)
            ans=sanfen2(-r,r);
            else
        ans=min(sanfen1(-r,r),sanfen2(-r,r));
        printf("%.7f\n",ans);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值