POJ 2074 Line of Sight(直線交點、最長連續區間)
阿新 • • 發佈:2020-12-15
大意:
給出一個房子的兩個端點座標,以及觀察線的左右端點座標,n個障礙物,問觀察線上能看到完整的房子的最長連續區間。
思路:
圖源:https://blog.csdn.net/weixin_43311695/article/details/109193862
算出每個障礙物導致的視野盲區,然後計算不在盲區的最長區間即可。這裡處理最長區間的方法是:將所有的盲區按照左端點排序,然後更新右邊區間和答案即可。還需要注意的是,如果障礙物不在房子和觀察線之間,那麼不需要考慮。
注意一個小trick:下標從1開始記錄盲區,因為這樣可以避免討論沒有盲區的情況
#include <math.h> #include <stdio.h> #include <string.h> #include <algorithm> #include <cstdio> #include <iostream> #include <map> #include <queue> #include <set> #include <vector> using namespace std; const int N = 1e6 + 5; typedef long long LL; double dis[100][100]; // 計算幾何模板 const double eps = 1e-8; const double inf = 1e20; const double pi = acos(-1.0); const int maxp = 1010; // 和0做比較 int sgn(double x) { if (fabs(x) < eps) return 0; // =0 if (x < 0) return -1; // < 0 else return 1; // > 0 } // 計算x的平方 inline double sqr(double x) { return x * x; } struct Point { double x, y; int index; 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); } 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 dist(Point p) { return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y)); } // 極角排序 }; struct Line { Point s, e; Line() {} // 兩點確定一條線段 Line(Point _s, Point _e) { s = _s; e = _e; } //返回點和直線(方向向量)關係 // 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; } //兩線段相交判斷:規範相交:交點不在端點 // 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); } bool parallel(Line v) { return sgn((e - s) ^ (v.e - v.s)) == 0; } //求兩直線的交點 //要保證兩直線不平行或重合 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 length() { return s.dist(e); } //點到直線的距離 double dispointtoline(Point p) { return fabs((p - s) ^ (e - s)) / length(); } //點到線段的距離 double dispointtoseg(Point p) { if (sgn((p - s) * (e - s)) < 0 || sgn((p - e) * (s - e)) < 0) return min(p.dist(s), p.dist(e)); return dispointtoline(p); } //直線和線段相交判斷 //-*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); } }; struct Seq { double left, right; Seq() {} Seq(double _left, double _right) { left = _left; right = _right; } }; Seq seq[N]; bool cmp(Seq a, Seq b) { return a.left < b.left; } double x1, x2, y, px1, px2, py; Line property, ob[N]; int n, cnt; int main() { while (scanf("%lf%lf%lf", &x1, &x2, &y) != EOF && (x1 + x2 + y != 0)) { scanf("%lf%lf%lf", &px1, &px2, &py); property = Line(Point(px1, py), Point(px2, py)); scanf("%d", &n); cnt = 0; seq[0] = Seq(0.0, 0.0); for (int i = 1; i <= n; i++) { double ox1, ox2, oy; scanf("%lf%lf%lf", &ox1, &ox2, &oy); if (oy >= y || oy <= py) continue; Line now = Line(Point(x2, y), Point(ox1, oy)); Point lx = now.crosspoint(property); if (lx.x >= px2) continue; if (lx.x < px1) lx.x = px1; now = Line(Point(x1, y), Point(ox2, oy)); Point rx = now.crosspoint(property); if (rx.x <= px1) continue; if (rx.x > px2) rx.x = px2; seq[++cnt] = Seq(lx.x, rx.x); } sort(seq + 1, seq + cnt + 1, cmp); double res = 0, r = px1; for (int i = 1; i <= cnt; i++) { res = max(res, seq[i].left - r); r = max(r, seq[i].right); } res = max(res, px2 - r); if (sgn(res) == 0) printf("No View\n"); else printf("%.2f\n", res); } }