POJ 1039 - Pipe
http://poj.org/problem?id=1039
概要
座標の列 (x[1], y[1]), ..., (x[n], y[n]) が与えられ,(x[1], y[1]), ..., (x[n], y[n]) と (x[1], y[1]-1), ..., (x[n], y[n]-1) からなるパイプを示している (図を見ると意味がわかりやすい).
(x[1], y[1]) のほうからパイプ内に光を当てたとき,到達しうる最大の x 座標を答える. ただし,パイプを抜ける場合は「Through all the pipe.」と出力する.
パイプは全く光を通さないし,全く反射もしないとする.
制約
- 2 <= n <= 20
- x[1] < x[2] < ... < x[n]
解法
直線が最も右側まで伸びるのは
- (x[i], y[i]) と (x[j], y[j]-1) を結んだ直線 (i < j)
- (x[i], y[i]-1) と (x[j], y[j]) を結んだ直線 (i < j)
のいずれか.
last_index()
でそのような直線がどこまで進めるかを計算し,もし n 番目まで進めるならすぐに「Through all the pipe.」を出力し,そうでなかったら last_index()
の次の区間での交点を計算して最大値をとる,というように実装した.
poj/1039.cc1 #include <cstdio> 2 #include <iostream> 3 #include <vector> 4 #include <complex> 5 #include <limits> 6 using namespace std; 7 typedef complex<double> P; 8 static const double EPS = 1e-6; 9 10 inline bool feq(double x, double y) { return abs(x - y) < EPS; } 11 inline bool fleq(double x, double y) { return x <= y + EPS; } 12 inline double cross(const P& a, const P& b) { return a.real()*b.imag() - b.real()*a.imag(); } 13 14 struct line 15 { 16 P a, b; 17 line(const P& x, const P& y) : a(x), b(y) {} 18 }; 19 20 struct segment 21 { 22 P a, b; 23 segment(const P& x, const P& y) : a(x), b(y) {} 24 inline bool intersects(const line& ln) const 25 { 26 return cross(ln.b-ln.a, a-ln.a) * cross(ln.b-ln.a, b-ln.a) < EPS; 27 } 28 29 inline P intersection(const line& ln) const 30 { 31 const P x = b - a; 32 const P y = ln.b - ln.a; 33 return a + x*(cross(y, ln.a-a)/cross(y, x)); 34 } 35 }; 36 37 int last_index(const vector<pair<P,P> >& v, const P& left, const P& right) 38 { 39 const int N = v.size(); 40 const P e = (right - left) / abs(right - left); 41 for (int i = 0; i < N; i++) { 42 const double scale = (v[i].first.real() - left.real()) / e.real(); 43 P p = left + scale*e; 44 if (!fleq(v[i].second.imag(), p.imag()) || !fleq(p.imag(), v[i].first.imag())) { 45 return i-1; 46 } 47 } 48 return N-1; 49 } 50 51 double update(double ans, const P& left, const P& right, const pair<P,P>& beg, const pair<P,P>& end) 52 { 53 const line ln(left, right); 54 const segment s1(beg.first, end.first); 55 const segment s2(beg.second, end.second); 56 if (s1.intersects(ln)) { 57 ans = max(ans, s1.intersection(ln).real()); 58 } 59 if (s2.intersects(ln)) { 60 ans = max(ans, s2.intersection(ln).real()); 61 } 62 return ans; 63 } 64 65 int main() 66 { 67 int N; 68 while (scanf("%d", &N) != EOF && N != 0) { 69 vector<pair<P,P> > v(N); 70 for (int i = 0; i < N; i++) { 71 double x, y; 72 scanf("%lf %lf", &x, &y); 73 v[i] = make_pair(P(x, y), P(x, y-1)); 74 } 75 76 double ans = -numeric_limits<double>::max(); 77 for (int i = 0; i < N; i++) { 78 for (int j = i+1; j < N; j++) { 79 const int k = last_index(v, v[i].first, v[j].second); 80 const int l = last_index(v, v[i].second, v[j].first); 81 if (max(k, l) == N-1) { 82 puts("Through all the pipe."); 83 goto NEXT; 84 } else { 85 if (j <= k) { 86 ans = update(ans, v[i].first, v[j].second, v[k], v[k+1]); 87 } 88 if (j <= l) { 89 ans = update(ans, v[i].second, v[j].first, v[l], v[l+1]); 90 } 91 } 92 } 93 } 94 printf("%.2f\n", ans); 95 NEXT: 96 ; 97 } 98 return 0; 99 }