题意:甲乙两人看完电影准备回家,乙想直接回家,甲想先去超市再回家,已知甲可以多走t1的“冤枉路”,乙可以多走t2的“冤枉路”,问甲乙最多同行多远后分离
题解:设甲最多走L1,乙最多走L2,
首先如果乙b能陪伴甲全程(即L2≥Distance(A,C)+Distance(C,B))L2≥Distance(A,C)+Distance(C,B)),那么答案显然为min(L1,L2) 。
如若不然,显然答案是单调的,可以二分查找
不妨设分离点为P,当前二分到mid,那么:
Distance(P,A)≤mid
Distance(P,B)≤L2−mid
Distance(P,C)≤L1−Distance(B,C)−mid
即:
设分离点为P,那么点P必须满足以下三个条件:
P必须在以A为圆心半径为x的圆内,因为他们走的公共距离为x
P必须在以B为圆心半径为L2−x的圆内,为了让乙在分开之后能及时返回B点
P必选在以C为圆心半径为L1−x−BC的圆内,因为甲在到达C之后还要径直走回B点。
于是问题就转换成判断三个圆相交的问题,就可以套模板了
#include <bits/stdc++.h>
#define point complex<double>
using namespace std;
const double eps = 1e-8;
double t1, t2;
point cinema, shop, house;
void readpoint(point &p){
double x, y;
scanf("%lf %lf", &x, &y);
p = point(x, y);
}
bool inter(point a, double r_a, point b, double r_b, point c, double r_c){ //以c为主圆求a b焦点判相交
if (abs(c - a) <= r_a && abs(c - b) <= r_b) return true;
b -= a;
c -= a; //以a为原点
point r = point(b.real() / abs(b), b.imag() / abs(b)); //将x轴正方向置为b
b /= r;
c /= r;
double d = (r_a * r_a - r_b * r_b + abs(b) * abs(b)) / (2 * abs(b));
double h = sqrt(max(r_a * r_a - d * d, 0.0));
if (abs(h * h + (d - abs(b)) * (d - abs(b))) - r_b * r_b > eps) return false;
if (abs(point(d, h) - c) <= r_c || abs(point(d, -h) - c) <= r_c) return true;
return false;
}
bool check(point a, double r_a, point b, double r_b, point c, double r_c){ //判断三圆是否相交
if (r_a <= eps || r_b <= eps || r_c <= eps) return false; //有空集
r_a = max(r_a, 0.0);
r_b = max(r_b, 0.0);
r_c = max(r_c, 0.0);
if (inter(a, r_a, c, r_c, b, r_b)) return true;
if (inter(b, r_b, a, r_a, c, r_c)) return true;
if (inter(c, r_c, b, r_b, a, r_a)) return true;
return false;
}
int main(){
scanf("%lf %lf", &t1, &t2);
readpoint(cinema);
readpoint(house);
readpoint(shop);
if (abs(shop - cinema) + abs(house - shop) <= abs(cinema - house) + t2){ //Alan <= Bob + t2
printf("%lf\n", min(abs(cinema - house) + t2, abs(shop - cinema) + abs(house - shop) + t1));
}
else{
double l, r, mid;
l = 0;
r = min(abs(cinema - house) + t2, abs(shop - cinema) + abs(house - shop) + t1);
for(int i = 1; i <= 200; i ++){
mid = (r + l) / 2;
if (check(cinema, mid, shop, abs(shop - cinema) + t1 - mid, house, abs(house - cinema) + t2 - mid)){
l = mid;
}
else {
r = mid;
}
}
printf("%.4lf\n", l);
}
return 0;
}