poj 1263 Reflections (Simple Geometry)
简单计算几何。题目给出射线以及若干个不相交的圆,求出射线会在哪些圆上反弹,依次写出反弹球的编号。
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <vector> 7 8 using namespace std; 9 10 const double EPS = 1e-10; 11 template<class T> T sqr(T x) { return x * x;} 12 inline int sgn(double x) { return (x > EPS) - (x < -EPS);} 13 struct Point { 14 double x, y; 15 Point() {} 16 Point(double x, double y) : x(x), y(y) {} 17 bool operator < (Point a) const { return sgn(x - a.x) < 0 || sgn(x - a.x) == 0 && y < a.y;} 18 bool operator == (Point a) const { return sgn(x - a.x) == 0 && sgn(y - a.y) == 0;} 19 Point operator + (Point a) { return Point(x + a.x, y + a.y);} 20 Point operator - (Point a) { return Point(x - a.x, y - a.y);} 21 Point operator * (double p) { return Point(x * p, y * p);} 22 Point operator / (double p) { return Point(x / p, y / p);} 23 } ; 24 typedef Point Vec; 25 26 inline double cross(Vec a, Vec b) { return a.x * b.y - a.y * b.x;} 27 inline double cross(Point o, Point a, Point b) { return cross(a - o, b - o);} 28 inline double dot(Vec a, Vec b) { return a.x * b.x + a.y * b.y;} 29 inline double dot(Point o, Point a, Point b) { return dot(a - o, b - o);} 30 inline double veclen(Vec x) { return sqrt(dot(x, x));} 31 inline Vec normal(Vec x) { return Vec(-x.y, x.x) / veclen(x);} 32 33 struct Line { 34 Point s, t; 35 Line() {} 36 Line(Point s, Point t) : s(s), t(t) {} 37 Vec vec() { return t - s;} 38 Point pt(double x) { return s + vec() * x;} 39 Line move(double x) { 40 Vec nor = normal(vec()); 41 return Line(s + nor * x, t + nor * x); 42 } 43 } ; 44 45 inline Point llint(Point P, Vec v, Point Q, Vec w) { return P + v * (cross(w, P - Q) / cross(v, w));} 46 inline Point llint(Line a, Line b) { return llint(a.s, a.vec(), b.s, b.vec());} 47 48 struct Circle { 49 Point c; 50 double r; 51 Circle() {} 52 Circle(Point c, double r) : c(c), r(r) {} 53 } ; 54 55 void lcint(Line L, Circle C, vector<Point> &sol) { 56 Point ip = llint(L, Line(C.c, C.c + normal(L.vec()))); 57 double dis = veclen(ip - C.c); 58 if (sgn(dis - C.r) >= 0) return ; 59 Vec u = L.vec() / veclen(L.vec()); 60 double d = sqrt(sqr(C.r) - sqr(dis)); 61 sol.push_back(ip + u * d); 62 sol.push_back(ip - u * d); 63 } 64 65 Point reflect(Point x, Line L) { 66 Vec nor = normal(L.vec()); 67 Point ip = llint(L, Line(x, x + nor)); 68 return ip + ip - x; 69 } 70 71 vector<Circle> rec; 72 Point src; 73 Vec dir; 74 75 const double FINF = 1e100; 76 inline bool onCircle(Point p, Circle c) { return sgn(veclen(p - c.c) - c.r) == 0;} 77 78 void work() { 79 int cnt = 0, sz = rec.size(); 80 vector<Point> tmp; 81 Point ip; 82 while (true) { 83 tmp.clear(); 84 double d = FINF; 85 for (int i = 0; i < sz; i++) lcint(Line(src, src + dir), rec[i], tmp); 86 for (int i = 0, sz = tmp.size(); i < sz; i++) { 87 double t = (tmp[i].x - src.x) / dir.x; 88 if (t > EPS) d = min(d, t); 89 } 90 if (sgn(d - FINF) >= 0) break; 91 cnt++; 92 if (cnt > 10) break; 93 ip = src + dir * d; 94 int mk = -1; 95 for (int i = 0; i < sz; i++) if (onCircle(ip, rec[i])) { mk = i; break;} 96 if (mk == -1) { puts("shit!!"); while (1) ;} 97 printf("%d ", mk + 1); 98 dir = reflect(src, Line(ip, rec[mk].c)) - ip; 99 src = ip; 100 } 101 if (cnt > 10) puts("..."); 102 else puts("inf"); 103 } 104 105 int main() { 106 // freopen("in", "r", stdin); 107 int cas = 1, n; 108 double x, y, r; 109 while (cin >> n && n) { 110 rec.clear(); 111 while (n--) { 112 cin >> x >> y >> r; 113 rec.push_back(Circle(Point(x, y), r)); 114 } 115 cin >> src.x >> src.y; 116 cin >> dir.x >> dir.y; 117 dir = dir / veclen(dir); 118 printf("Scene %d\n", cas++); 119 work(); 120 puts(""); 121 } 122 return 0; 123 }
速度好慢,整整写了一个小时。对几何模板还是不算非常熟悉,虽然已经能够灵活写出部分基础函数了,但是速度还真是一个大问题。最后结果,因为手多血多个换行PE了一次,然后就AC了~
——written by Lyon