Urban Design(计算几何,判断直线与线段是否相交)

Urban Design

A new town is being planned, and the designers have some very specific ideas about how things should be laid out. First, they lay out the streets. Each street is perfectly straight and passes completely from one end of the town to the other. These streets divide the town into regions, and each region is to be designated either"residential"or"commercial".The town planners require that any two regions directly across the street from one another must have different designations. On this one particular day, all of the streets have been planned, but none of the regions have been designated. One town planner wishes to purchase two properties, and it is important to him that the properties eventually have different designations. For this problem, the streets can be modeled by lines in the plane that extend forever in both directions and have no width, and properties may be modeled by points. Given the lines and two points, can you decide whether or not they must get different designations,“commercial"or"residential”?
在这里插入图片描述

Input

Input begins with an integer S on a single line, giving the number of streets (1≤S≤10000). The next S lines of input each contain four integers x1, y1, x2, and y2, specifying the coordinates of two distinct points (x1, y1) and (x2, y2). The unique line through these two points gives one of the streets. Each coordinate is in the range [0,10000], and no two lines will be identical. That is, the town will have S distinct streets. The next line contains an integer T, the number of pairs of properties to test (1≤T≤1000). This is followed by T lines of input, each containing four integers x3, y3, x4 and y4, representing two distinct points (x3,y3) and (x4,y4), where each point lies within one of the two properties to test. None of these points will lie on any of the streets, nor will both points lie within the same property. Again, each coordinate is in the range [0,10000].

Output

For each of the T pairs of properties to be tested, output either"same"if the properties are guaranteed to receive the same designation or"different"if they are guaranteed to receive different designations.

样例输入1

2
1 1 2 1
1 1 1 2
3
2 0 2 2
2 0 0 3
0 0 2 2

样例输出1

different
same
same

样例输入2

4
1 3 2 4
1 3 2 5
1 3 3 4
7 9 8 8
2
14 7 10 13
1 4 2 3

样例输出2

same
different

实现代码
#include <bits/stdc++.h>

using namespace std;

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

typedef long long ll;

const int inf = 0x3f3f3f3f;
const int maxn = 1e4 + 50;
const double eps = 1e-8;
const double pi = acos(-1.0);

inline double sqr(double x) { return x * x; }

int sgn(double x) {
    if (fabs(x) < eps)return 0;
    if (x < 0) return -1;
    return 1;
}

struct Point {
    double x, y;

    Point() {}

    Point(double xx, double yy) { x = xx, y = yy; }

    void input() { scanf("%lf%lf", &x, &y); }

    void output() { printf("%f %f\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);
    }

    Point operator/(const double &k) const {
        return Point(x / k, y / k);
    }

    //数乘
    Point operator*(const double &k) const {
        return Point(x * k, y * k);
    }

    //点乘
    double operator*(const Point &b) const {
        return x * b.x + y * b.y;
    }

    //叉乘
    double operator^(const Point &b) const {
        return x * b.y - y * b.x;
    }

    //和原点的距离
    double len() { return hypot(x, y); }

    //长度的平方
    double len2() { return x * x + y * y; }

    //两点距离
    inline double distance(Point p) {
        return hypot(x - p.x, y - p.y);
    }

    //与a、b两点的夹角
    double rad(Point a, Point b) {
        Point p = *this;
        return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p) * (b - p)));
    }
};

struct Line {
    Point s, e;

    Line() {}

    Line(Point ss, Point ee) { s = ss, e = ee; }

    bool operator==(Line v) {
        return (s == v.s) && (e == v.e);
    }

    //根据点和倾斜角确定直线,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);
        }
    }

    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);
    }

    //直线和线段相交判断 2规范相交 1非规范 0不相交
    //*this:line  v:seg
    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 (sgn((p - s) * (e - s)) < 0 || sgn((p - e) * (s - e)) < 0)
            return min(p.distance(s), p.distance(e));
        return dispointtoline(p);
    }

    //两平行线段距离
    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;
};
Line l[maxn], se[maxn];

int main() {
    int s = read();
    for (int i = 0; i < s; i++) {
        l[i].s.input();
        l[i].e.input();
    }
    int t = read();
    for (int i = 0; i < t; i++) {
        se[i].s.input();
        se[i].e.input();
        int cnt = 0;
        for (int j = 0; j < s; j++) {
            if (l[j].linecrossseg(se[i]) == 2) cnt++;
        }
        if (cnt & 1) puts("different");
        else puts("same");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值