NC245395. Magic Mirrors
描述
输入描述
The fifirst line contains an integer T(1 ≤ T ≤ 2 × 105 ), indicating the number of test cases.Each test case contains three lines. In the fifirst line, there are three integers A1, B1, C1(−109 ≤ A1, B1, C1 ≤ 109 ) denoting a magic mirror which can be recognized as a line A1x + B1y + C1 = 0. In the second line, there are three integers A2, B2, C2(−109 ≤ A2, B2, C2 ≤ 109 ) denoting another magic mirror. In the third line, there are four integers px, py, qx, qy(−109 ≤ px, py, qx, qy ≤ 109) denoting the position of Sil and the position he wants to go.
输出描述
For each test case, output a real number in a single line, indicating the minimum distance between Sil or one copy of Sil and the target place. Your answer will be considered correct if the relative or absolute error between yours and the standard solution is not greater than 10−6 .
示例1
输入:
3 1 0 0 0 1 0 2 2 -3 -1 1 0 0 1 0 -1 2 2 -3 -1 1 2 0 3 4 0 2 2 -3 -1
输出:
1.4142135624 3.1622776602 0.3338505354
C++(g++ 7.5.0) 解法, 执行用时: 903ms, 内存消耗: 4868K, 提交时间: 2022-10-25 20:09:05
#include <bits/stdc++.h> using namespace std; // `计算几何模板` const double eps = 1e-8; const double inf = 1e20; const double pi = acos(-1.0); const int maxp = 1010; //`Compares a double to zero` int sgn(double x){ if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1; } //square of a double inline double sqr(double x){return x*x;} /* * Point * Point() - Empty constructor * Point(double _x,double _y) - constructor * input() - double input * output() - %.2f output * operator == - compares x and y * operator < - compares first by x, then by y * operator - - return new Point after subtracting curresponging x and y * operator ^ - cross product of 2d points * operator * - dot product * len() - gives length from origin * len2() - gives square of length from origin * distance(Point p) - gives distance from p * operator + Point b - returns new Point after adding curresponging x and y * operator * double k - returns new Point after multiplieing x and y by k * operator / double k - returns new Point after divideing x and y by k * rad(Point a,Point b)- returns the angle of Point a and Point b from this Point * trunc(double r) - return Point that if truncated the distance from center to r * rotleft() - returns 90 degree ccw rotated point * rotright() - returns 90 degree cw rotated point * rotate(Point p,double angle) - returns Point after rotateing the Point centering at p by angle radian ccw */ 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\n",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); } //`计算pa 和 pb 的夹角` //`就是求这个点看a,b 所成的夹角` //`测试 LightOJ1203` double rad(Point a,Point b){ Point p = *this; return fabs(atan2( fabs((a-p)^(b-p)),(a-p)*(b-p) )); } //`化为长度为r的向量` Point trunc(double r){ double l = len(); if(!sgn(l))return *this; r /= l; return Point(x*r,y*r); } //`逆时针旋转90度` Point rotleft(){ return Point(-y,x); } //`顺时针旋转90度` Point rotright(){ return Point(y,-x); } //`绕着p点逆时针旋转angle` Point rotate(Point p,double angle){ Point v = (*this) - p; double c = cos(angle), s = sin(angle); return Point(p.x + v.x*c - v.y*s,p.y + v.x*s + v.y*c); } double compare(Point a,Point b,Point c){ //计算极角 Point A(b.x-a.x,b.y-a.y); Point B(c.x-a.x,c.y-a.y); return A*B; } //利用atan进行极角排序,精度较低,效率高; 返回3 4 1 2 象限 bool cmp(Point a,Point b){ if(atan2(a.y,a.x)!=atan2(b.y,b.x)) return atan2(a.y,a.x)<atan2(b.y,b.x); return a.x<b.x; } }; /* * Stores two points * Line() - Empty constructor * Line(Point _s,Point _e) - Line through _s and _e * operator == - checks if two points are same * Line(Point p,double angle) - one end p , another end at angle degree * Line(double a,double b,double c) - Line of equation ax + by + c = 0 * input() - inputs s and e * adjust() - orders in such a way that s < e * length() - distance of se * angle() - return 0 <= angle < pi * relation(Point p) - 3 if point is on line * 1 if point on the left of line * 2 if point on the right of line * pointonseg(double p) - return true if point on segment * parallel(Line v) - return true if they are parallel * segcrossseg(Line v) - returns 0 if does not intersect * returns 1 if non-standard intersection * returns 2 if intersects * linecrossseg(Line v) - line and seg * linecrossline(Line v) - 0 if parallel * 1 if coincides * 2 if intersects * crosspoint(Line v) - returns intersection point * dispointtoline(Point p) - distance from point p to the line * dispointtoseg(Point p) - distance from p to the segment * dissegtoseg(Line v) - distance of two segment * lineprog(Point p) - returns projected point p on se line * symmetrypoint(Point p) - returns reflection point of p over se * */ struct Line{ Point s,e; Line(){} Line(Point _s,Point _e){ s = _s; e = _e; } bool operator ==(Line v){ return (s == v.s)&&(e == v.e); } //`根据一个点和倾斜角angle确定直线,0<=angle<pi` Line(Point p,double angle){ s = p; if(sgn(angle-pi/2) == 0){ e = (s + Point(0,1)); } else{ e = (s + Point(1,tan(angle))); } } //ax+by+c=0 Line(double a,double b,double c){ if(sgn(a) == 0){ s = Point(0,-c/b); e = Point(1,-c/b); } else if(sgn(b) == 0){ s = Point(-c/a,0); e = Point(-c/a,1); } else{ s = Point(0,-c/b); e = Point(1,(-c-a)/b); } } void input(){ s.input(); e.input(); } void adjust(){ if(e < s)swap(s,e); } //求线段长度 double length(){ return s.distance(e); } //`返回直线倾斜角 0<=angle<pi` double angle(){ double k = atan2(e.y-s.y,e.x-s.x); if(sgn(k) < 0)k += pi; if(sgn(k-pi) == 0)k -= pi; return k; } //`点和直线关系` //`1 在左侧` //`2 在右侧` //`3 在直线上` int relation(Point p){ int c = sgn((p-s)^(e-s)); if(c < 0)return 1; else if(c > 0)return 2; else return 3; } // 点在线段上的判断 bool pointonseg(Point p){ return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0; } //`两向量平行(对应直线平行或重合)` bool parallel(Line v){ return sgn((e-s)^(v.e-v.s)) == 0; } //`两线段相交判断` //`2 规范相交` //`1 非规范相交` //`0 不相交` int segcrossseg(Line v){ int d1 = sgn((e-s)^(v.s-s)); int d2 = sgn((e-s)^(v.e-s)); int d3 = sgn((v.e-v.s)^(s-v.s)); int d4 = sgn((v.e-v.s)^(e-v.s)); if( (d1^d2)==-2 && (d3^d4)==-2 )return 2; return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) || (d2==0 && sgn((v.e-s)*(v.e-e))<=0) || (d3==0 && sgn((s-v.s)*(s-v.e))<=0) || (d4==0 && sgn((e-v.s)*(e-v.e))<=0); } //`直线和线段相交判断` //`-*this line -v seg` //`2 规范相交` //`1 非规范相交` //`0 不相交` int linecrossseg(Line v){ int d1 = sgn((e-s)^(v.s-s)); int d2 = sgn((e-s)^(v.e-s)); if((d1^d2)==-2) return 2; return (d1==0||d2==0); } //`两直线关系` //`0 平行` //`1 重合` //`2 相交` int linecrossline(Line v){ if((*this).parallel(v)) return v.relation(s)==3; return 2; } //`求两直线的交点` //`要保证两直线不平行或重合` Point crosspoint(Line v){ double a1 = (v.e-v.s)^(s-v.s); double a2 = (v.e-v.s)^(e-v.s); return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1)); } //点到直线的距离 double dispointtoline(Point p){ return fabs((p-s)^(e-s))/length(); } //点到线段的距离 double dispointtoseg(Point p){ if(s == e) return p.distance(s); if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0) return min(p.distance(s),p.distance(e)); return dispointtoline(p); } //`返回线段到线段的距离` //`前提是两线段不相交,相交距离就是0了` double dissegtoseg(Line v){ return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e))); } //`返回点p在直线上的投影` Point lineprog(Point p){ return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) ); } //`返回点p关于直线的对称点` Point symmetrypoint(Point p){ Point q = lineprog(p); return Point(2*q.x-p.x,2*q.y-p.y); } }; //圆 struct circle{ Point p;//圆心 double r;//半径 circle(){} circle(Point _p,double _r){ p = _p; r = _r; } circle(double x,double y,double _r){ p = Point(x,y); r = _r; } //`三角形的外接圆` //`需要Point的+ / rotate() 以及Line的crosspoint()` //`利用两条边的中垂线得到圆心` //`测试:UVA12304` circle(Point a,Point b,Point c){ Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft())); Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft())); p = u.crosspoint(v); r = p.distance(a); } //`三角形的内切圆` //`参数bool t没有作用,只是为了和上面外接圆函数区别` //`测试:UVA12304` circle(Point a,Point b,Point c,bool t){ Line u,v; double m = atan2(b.y-a.y,b.x-a.x), n = atan2(c.y-a.y,c.x-a.x); u.s = a; u.e = u.s + Point(cos((n+m)/2),sin((n+m)/2)); v.s = b; m = atan2(a.y-b.y,a.x-b.x) , n = atan2(c.y-b.y,c.x-b.x); v.e = v.s + Point(cos((n+m)/2),sin((n+m)/2)); p = u.crosspoint(v); r = Line(a,b).dispointtoseg(p); } //`点和圆的关系` //`0 圆外` //`1 圆上` //`2 圆内` int relation(Point b){ double dst = b.distance(p); if(sgn(dst-r) < 0)return 2; else if(sgn(dst-r)==0)return 1; return 0; } }; typedef double db; #define sqr(x) ((x)*(x)) int main(){ int t; scanf("%d", &t); while(t --){ Line a, b; db p1[3], p2[3]; for(int i = 0;i < 3;i ++) scanf("%lf", &p1[i]); a = {p1[0], p1[1], p1[2]}; for(int i = 0;i < 3;i ++) scanf("%lf", &p2[i]); b = {p2[0], p2[1], p2[2]}; db ans = 1e20; Point q1, q2, f[8]; scanf("%lf %lf %lf %lf", &q1.x, &q1.y, &q2.x, &q2.y); if(a.linecrossline(b)==2){ if(p1[0]*p2[0]+p1[1]*p2[1]==0){//垂直 f[0] = q1; f[1] = a.symmetrypoint(q1); f[2] = b.symmetrypoint(q1); f[3] = b.symmetrypoint(f[1]); for(int i = 0;i < 4;i ++) ans = min(ans, f[i].distance(q2)); }else{//交叉 Point o = a.crosspoint(b); db R = o.distance(q1); circle C = {o, R}; if(C.relation(q2)) ans = C.r-q2.distance(C.p); else ans = q2.distance(C.p)-C.r; } } else if(a.linecrossline(b) == 1){//重合 f[0] = q1, f[1] = a.symmetrypoint(f[0]); for(int i = 0;i < 2;i ++) ans = min(ans, f[i].distance(q2)); } else{// 平行 Line v = {q1, a.symmetrypoint(q1)}; db d1 = a.dispointtoline(q1), d2 = a.dispointtoline(q2), d3 = a.dispointtoline(b.s); db a3 = -p1[1], b3 = p1[0], c3 = p1[1] * q1.x - p1[0] * q1.y; db t1 = floor((d2 - d1) / (2 * d3)), t2 = ceil((d2 - d1) / (2 * d3)), t3 = floor((d1 + d2) / (2 * d3)), t4 = ceil((d1 + d2) / (2 * d3)); db b1 = min({abs(d2 - d1 - 2 * d3 * t1), abs(d2 - d1 - 2 * d3 * t2), abs(d1 + d2 - 2 * d3 * t3), abs(d1 + d2 - 2 * d3 * t4)}), b2 = abs(a3 * q2.x + b3 * q2.y + c3) / sqrt(sqr(a3) + sqr(b3)); ans = sqrt(sqr(b1) + sqr(b2)); } printf("%.12lf\n", ans); } return 0; }
C++(clang++ 11.0.1) 解法, 执行用时: 694ms, 内存消耗: 4432K, 提交时间: 2022-12-11 10:25:15
#include <bits/stdc++.h> #define LD long double using namespace std; int read() { int ret = 0; scanf("%d", &ret); return ret; } LD sqr(LD x) { return x * x; } void symmetry(LD a, LD b, LD c, LD &x, LD &y) { LD x0 = x, y0 = y; x = ((sqr(b) - sqr(a)) * x0 - 2 * a * b * y0 - 2 * a * c) / (sqr(a) + sqr(b)); y = ((sqr(a) - sqr(b)) * y0 - 2 * a * b * x0 - 2 * b * c) / (sqr(a) + sqr(b)); } LD dis(LD x1, LD y1, LD x2, LD y2) { return sqrt(sqr(x1 - x2) + sqr(y1 - y2)); } void work() { LD a1 = read(), b1 = read(), c1 = read(), a2 = read(), b2 = read(), c2 = read(), px = read(), py = read(), qx = read(), qy = read(); if (!(a1 * a2 + b1 * b2)) { LD ans = dis(px, py, qx, qy); symmetry(a1, b1, c1, px, py); ans = min(ans, dis(px, py, qx, qy)); symmetry(a2, b2, c2, px, py); ans = min(ans, dis(px, py, qx, qy)); symmetry(a1, b1, c1, px, py); ans = min(ans, dis(px, py, qx, qy)); printf("%.10LF\n", ans); } else if (a1 * b2 == a2 * b1) { LD p = (a1 * px + b1 * py + c1) / sqrt(sqr(a1) + sqr(b1)), q = (a1 * qx + b1 * qy + c1) / sqrt(sqr(a1) + sqr(b1)), l = (c1 - c2) / sqrt(sqr(a1) + sqr(b1)); if (a1 * a2 < 0 || b1 * b2 < 0) l = -l; LD a3 = -b1, b3 = a1, c3 = b1 * px - a1 * py; LD t1 = floor((q - p) / (2 * l)), t2 = ceil((q - p) / (2 * l)), t3 = floor((q + p) / (2 * l)), t4 = ceil((q + p) / (2 * l)); LD d1 = min({abs(q - p - 2 * l * t1), abs(q - p - 2 * l * t2), abs(q + p - 2 * l * t3), abs(q + p - 2 * l * t4)}), d2 = abs(a3 * qx + b3 * qy + c3) / sqrt(sqr(a3) + sqr(b3)); printf("%.10LF\n", sqrt(sqr(d1) + sqr(d2))); } else { LD X = 1.0 * (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1), Y = 1.0 * (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1); LD ans = abs(dis(X, Y, px, py) - dis(X, Y, qx, qy)); printf("%.10LF\n", ans); } } int main() { int T = read(); while (T--) work(); }