1. 程式人生 > 實用技巧 >POJ 2074 Line of Sight(直線交點、最長連續區間)

POJ 2074 Line of Sight(直線交點、最長連續區間)

大意:

給出一個房子的兩個端點座標,以及觀察線的左右端點座標,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);
    }
}