codeforces #8D Two Friends 二分答案+计算几何

题目大意:给定平面上的三个点 A,B,C Alan 需要从 A 走到 C 再走到 B Bob 需要从 A 直接走到 B ,要求 Alan 走过的长度不能超过最短路长度+ t1 Bob 走过的长度不能超过最短路长度+ t2 ,求两人在一起最多走多久(分开后再汇合不算一起走)

Alan 最多走 L1 Bob 最多走 L2
首先如果 Bob 能陪伴 Alan 全程(即 L2Distance(A,C)+Distance(C,B) ),那么答案显然为 min(L1,L2)
否则两人分离时 Bob 一定还没有经过 C
容易发现答案是单调的,我们不妨二分答案
不妨设分离点为 P ,当前二分到 mid ,那么:
Distance(P,A)mid
Distance(P,B)L2mid
Distance(P,C)L1Distance(B,C)mid
容易发现每个不等式中 P 的范围都是一个圆
因此我们只需要判断三个圆是否有公共部分即可
具体怎么做自己玩去吧 注意精度

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define EPS 1e-15
#define PI 3.1415926535897932
using namespace std;
typedef long double ld;
struct Point{
    ld x,y;
    Point() {}
    Point(ld _,ld __):
        x(_),y(__) {}
    friend istream& operator >> (istream &_,Point &p)
    {
        return _>>p.x>>p.y;
    }
    friend Point operator + (const Point &p1,const Point &p2)
    {
        return Point(p1.x+p2.x,p1.y+p2.y);
    }
    friend Point operator - (const Point &p1,const Point &p2)
    {
        return Point(p1.x-p2.x,p1.y-p2.y);
    }
    friend ld Distance(const Point &p1,const Point &p2)
    {
        return sqrt( (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y) );
    }
    friend ld Arctan2(const Point &p)
    {
        return atan2(p.y,p.x);
    }
}A,B,C;
struct Interval{
    ld l,r;
    Interval() {}
    Interval(ld _,ld __):
        l(_),r(__) {}
    bool In_Interval(ld x) const
    {
        return x>=l && x<=r ;
    }
    friend bool Intersect(const Interval &i1,const Interval &i2)
    {
        return i1.In_Interval(i2.l) || i1.In_Interval(i2.r) || i2.In_Interval(i1.l) ;
    }
};
struct Circle{
    Point o;
    ld r;
    Circle() {}
    Circle(const Point &_,const ld &__):
        o(_),r(__) {}
    friend bool Seperated(const Circle &c1,const Circle &c2)
    {
        return Distance(c1.o,c2.o) > c1.r + c2.r + EPS ;
    }
    friend bool Include(const Circle &c1,const Circle &c2)
    {
        return Distance(c1.o,c2.o) < fabs(c1.r-c2.r) ;
    }
    friend Interval Get_Intersection(const Circle &c1,const Circle &c2)
    {
        ld alpha=Arctan2(c2.o-c1.o);
        ld a=c1.r;
        ld b=Distance(c1.o,c2.o)-EPS;
        ld c=c2.r;
        ld delta=acos( (a*a+b*b-c*c)/(2*a*b) );
        return Interval(alpha-delta,alpha+delta);
    }
};

ld t1,t2;
bool Check(const Circle &c1,const Circle &c2,const Circle &c3)
{
    Interval i1=Get_Intersection(c1,c2);
    Interval i2=Get_Intersection(c1,c3);
    if( Intersect(i1,i2) )
        return true;
    i1.l+=2*PI;i1.r+=2*PI;
    if( Intersect(i1,i2) )
        return true;
    i1.l-=4*PI;i1.r-=4*PI;
    if( Intersect(i1,i2) )
        return true;
    return false;
}
bool Judge(ld mid)
{
    Circle c1(A,mid);
    Circle c2(B,t1-mid);
    Circle c3(C,t2-Distance(B,C)-mid);
    if( Seperated(c1,c2) || Seperated(c1,c3) || Seperated(c2,c3) )
        return false;
    if( Include(c1,c2) || Include(c1,c3) || Include(c2,c3) )
        return true;
    return Check(c1,c2,c3) || Check(c2,c1,c3) || Check(c3,c1,c2) ;
}
ld Bisection()
{
    ld l=0,r=min(t1,t2-Distance(B,C));
    while(r-l>EPS)
    {
        ld mid=(l+r)/2;
        if(Judge(mid))
            l=mid;
        else
            r=mid;
    }
    return (l+r)/2;
}
int main()
{
    cin>>t2>>t1>>A>>B>>C;
    t1+=Distance(A,B);
    t2+=Distance(A,C);
    t2+=Distance(B,C);
    if( t1>=Distance(A,C)+Distance(B,C) )
        return cout<<fixed<<setprecision(10)<<min(t1,t2)<<endl,0;
    cout<<fixed<<setprecision(10)<<Bisection()<<endl;
    return 0;
}

你可能感兴趣的:(codeforces,计算几何,二分答案)