题意:给你一个圆,其圆心O在(0,0),给出圆的半径R, 之后再给出圆内两点P,Q,满足|PO| = |QO|,在圆上找到一点D使得|QD| + |PD|最小。
思路:进行P和Q对这个圆的反演可以得到P'和Q'。易得|QD| + |PD|就是求|Q'D| + |P'D|的最小值(相似三角形)。之后分类讨论即可
注意特判P = Q的情况。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> using namespace std; const double eps = 1e-8; int sgn(double x) { if (fabs(x) < eps) return 0; return x < eps ? -1 : 1; } struct Point{ double x,y; Point(){} Point(double _x,double _y){ x = _x; y = _y; } void input(){ scanf("%lf%lf",&x,&y); } void output(){ printf("%.2f %.2f ",x,y); } bool operator == (Point b)const{ return sgn(x-b.x) == 0 && sgn(y-b.y) == 0; } bool operator < (Point b)const{ return sgn(x-b.x)== 0?sgn(y-b.y)<0:x<b.x; } Point operator -(const Point &b)const{ return Point(x-b.x,y-b.y); } //叉积 double operator ^(const Point &b)const{ return x*b.y - y*b.x; } //点积 double operator *(const Point &b)const{ return x*b.x + y*b.y; } //返回长度 double len(){ return hypot(x,y);//库函数 } //返回长度的平方 double len2(){ return x*x + y*y; } //返回两点的距离 double distance(Point p){ return hypot(x-p.x,y-p.y); } Point operator +(const Point &b)const{ return Point(x+b.x,y+b.y); } Point operator *(const double &k)const{ return Point(x*k,y*k); } Point operator /(const double &k)const{ return Point(x/k,y/k); } }; struct Circle{ Point p;//圆心 double r;//半径 Circle(){} }; /* 直线和原的交点 */ int getLineCircleIntersection (Point p, Point q, Circle O, vector<Point>& sol) { double t1, t2; Point v = q - p; sol.clear(); double a = v.x, b = p.x - O.p.x, c = v.y, d = p.y - O.p.y; double e = a*a+c*c, f = 2*(a*b+c*d), g = b*b+d*d-O.r*O.r; double delta = f*f - 4*e*g; if (sgn(delta) < 0) return 0; if (sgn(delta) == 0) { t1 = t2 = -f / (2 * e); sol.push_back(p + v * t1); return 1; } t1 = (-f - sqrt(delta)) / (2 * e); sol.push_back(p + v * t1); t2 = (-f + sqrt(delta)) / (2 * e); sol.push_back(p + v * t2); return 2; } int main() { int T; scanf("%d", &T); while (T--) { Circle O; scanf("%lf", &O.r); Point p, q; p.input(), q.input(); Point pp, qq; pp = p * (O.r*O.r / p.len() / p.len()); qq = q * (O.r*O.r / q.len() / q.len()); Point mid = (p + q) / 2.0; mid = mid * (O.r / mid.len()); vector<Point> CrossP; int num = getLineCircleIntersection(pp, qq, O, CrossP); double len; if (p == q) len = 2.0*(O.r - q.len()); else if (num) len = (CrossP[0]-p).len() + (CrossP[0]-q).len(); else len = 2.0*(mid-p).len(); printf("%.7f ", len); } return 0; }