An Easy Problem?! POJ - 2826

An Easy Problem?! POJ - 2826

在这里插入图片描述

线段交点

求解线段交点与求解直线交点大体一致,区别在于求解线段交点之前需要先判断一下两个线段是否相交。
之后都是利用比例算出交点。

WA1代码

刚开始理解错了题意,自以为上方被盖住的情况也是可以进水的QAQ。(果然脑子被天灵盖盖住也是可以进水的

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;
int const INF = 0x3f3f3f3f;
double const eps = 1e-8;

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

struct P {
    double x, y;

    P() {}

    P(double _x, double _y) : x(_x), y(_y) {}

    P operator-(const P &b) const {
        return P(x - b.x, y - b.y);
    }

    double operator^(const P &b) const {
        return x * b.y - b.x * y;
    }
};

struct L {
    P s, e;

    L() {}

    L(P _s, P _e) : s(_s), e(_e) {}

    pair<int, P> operator&(const L &b) const {
        P res = s;
        if (sgn((s - e) ^ (b.s - b.e)) == 0) {
            if (sgn((s - b.e) ^ (b.s - b.e)) == 0) {
                return make_pair(0, res);
            } else return make_pair(1, res);
        }
        double t = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e));
        res.x += (e.x - s.x) * t;
        res.y += (e.y - s.y) * t;
        return make_pair(2, res);
    }
};

bool inter(L a, L b) {
    return
            max(a.s.x, a.e.x) >= min(b.s.x, b.e.x) &&
            max(b.s.x, b.e.x) >= min(a.s.x, a.e.x) &&
            max(a.s.y, a.e.y) >= min(b.s.y, b.e.y) &&
            max(b.s.y, b.e.y) >= min(a.s.y, a.e.y) &&
            (sgn((b.s - a.e) ^ (a.s - a.e)) * sgn((b.e - a.e) ^ (a.s - a.e)) <= 0) &&
            (sgn((a.s - b.e) ^ (b.s - b.e)) * sgn((a.e - b.e) ^ (b.s - b.e)) <= 0);
}

L l1, l2;

// 少了判断遮掩的情况
bool zero() {
    if (!(inter(l1, l2))) return true;
    if ((l1.s.y == l1.e.y) || (l2.s.y == l2.e.y)) return true;
    return false;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%lf%lf%lf%lf", &l1.s.x, &l1.s.y, &l1.e.x, &l1.e.y);
        scanf("%lf%lf%lf%lf", &l2.s.x, &l2.s.y, &l2.e.x, &l2.e.y);
        if (zero()) printf("0.00\n");
        else {
            P a = (l1 & l2).second;
            // 下面所有的比较大小都是因为没有在开始的时候对两个端点进行比较交换的操作我裂开
            // 当时的想法是:取两个线段中各自比较高的那一点,即y比较大的那一点,然后从得到的两点中取y较小的一点。
            // 实际上思路确实如此hhhhh只是这里写得略有复杂(
            P l1x = (l1.s.y > l1.e.y ? l1.s : l1.e), l2x = (l2.s.y > l2.e.y ? l2.s : l2.e);
            P b;
            bool flag = false;
            if (l1x.y > l2x.y) {
                b = l2x;
                flag = true;
            } else b = l1x;
			// 这里思路是取到较矮的一个,即b,然后取另一线段与b所在的与x轴平行的直线的交点,想法是对的,但是实现上有一些问题。
            P c;
            if (flag) {
             	// 这里错了,b所在的线段在另一线段的哪一侧是未知的,故取max和min是有待商酌的。
                L tmp = L(P(max(l1.s.x, l1.e.x), b.y), b);
                c = (tmp & l1).second;
            } else {
                L tmp = L(P(max(l2.s.x, l2.e.x), b.y), b);
                c = (tmp & l2).second;
            }
            printf("%.2lf\n", fabs(((b - a) ^ (c - a)) / 2));
        }
    }
    return 0;
}

WA_N代码

再也不想用G++了QAQ,什么破东西,用G++过不了用C++一下就过了!

AC代码

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;
int const INF = 0x3f3f3f3f;
double const eps = 1e-8;

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

struct P {
    double x, y;

    P() {}

    P(double _x, double _y) : x(_x), y(_y) {}

    P operator-(const P &b) const {
        return P(x - b.x, y - b.y);
    }

    double operator^(const P &b) const {
        return x * b.y - b.x * y;
    }
};

struct L {
    P s, e;

    L() {}

    L(P _s, P _e) : s(_s), e(_e) {}

    pair<int, P> operator&(const L &b) const {
        P res = s;
        if (sgn((s - e) ^ (b.s - b.e)) == 0) {
            if (sgn((s - b.e) ^ (b.s - b.e)) == 0) {
                return make_pair(0, res);
            } else return make_pair(1, res);
        }
        double t = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e));
        res.x += (e.x - s.x) * t;
        res.y += (e.y - s.y) * t;
        return make_pair(2, res);
    }
};

bool inter(L a, L b) {
    return
            max(a.s.x, a.e.x) >= min(b.s.x, b.e.x) &&
            max(b.s.x, b.e.x) >= min(a.s.x, a.e.x) &&
            max(a.s.y, a.e.y) >= min(b.s.y, b.e.y) &&
            max(b.s.y, b.e.y) >= min(a.s.y, a.e.y) &&
            (sgn((b.s - a.e) ^ (a.s - a.e)) * sgn((b.e - a.e) ^ (a.s - a.e)) <= 0) &&
            (sgn((a.s - b.e) ^ (b.s - b.e)) * sgn((a.e - b.e) ^ (b.s - b.e)) <= 0);
}

L l1, l2;

bool zero() {
    if (!(inter(l1, l2))) return true;
    if ((l1.s.y == l1.e.y) || (l2.s.y == l2.e.y)) return true;
    // 判断掩盖的情况
    if (inter(L(l1.s, P(l1.s.x, 100000)), l2) || inter(L(l2.s, P(l2.s.x, 1000000)), l1)) return true;
    return false;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif
    int T;
    scanf("%d", &T);
    while (T--) {
        double x1, y1, x2, y2, x3, y3, x4, y4;
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);
        if (y1 < y2) {
            swap(x1, x2), swap(y1, y2);
        }
        if (y3 < y4) {
            swap(x3, x4), swap(y3, y4);
        }
        l1.s = P(x1, y1), l1.e = P(x2, y2);
        l2.s = P(x3, y3), l2.e = P(x4, y4);
        if (zero()) printf("0.00\n");
        else {
            P a = (l1 & l2).second;
            P b, c;
            if (l1.s.y > l2.s.y) {
                b = l2.s;
                // 左右取极限距离,这样就不需要判断较矮线段在另一线段的哪一侧了
                L tmp1 = L(P(100000, b.y), b), tmp2 = L(P(-100000, b.y), b);
                if (inter(tmp1, l1)) {
                    c = (tmp1 & l1).second;
                } else if (inter(tmp2, l1)) {
                    c = (tmp2 & l1).second;
                }
            } else {
                b = l1.s;
                L tmp1 = L(P(100000, b.y), b), tmp2 = L(P(-100000, b.y), b);
                if (inter(tmp1, l2)) {
                    c = (tmp1 & l2).second;
                } else if (inter(tmp2, l2)) {
                    c = (tmp2 & l2).second;
                }
            }
            printf("%.2lf\n", fabs(((b - a) ^ (c - a)) / 2.0));
        }
    }
    return 0;
}

优化代码

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

double const eps = 1e-8;

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

struct P {
    double x, y;

    P() {}

    P(double _x, double _y) : x(_x), y(_y) {}

    P operator-(const P &b) const {
        return P(x - b.x, y - b.y);
    }

    double operator^(const P &b) const {
        return x * b.y - b.x * y;
    }

};

struct L {
    P s, e;

    L() {}

    L(P _s, P _e) : s(_s), e(_e) {}

// 两直线位置关系的判断
    pair<int, P> operator&(const L &b) const {
        P res = s;
        if (sgn((s - e) ^ (b.s - b.e)) == 0) {
            if (sgn((s - b.e) ^ (b.s - b.e)) == 0) {
                return make_pair(0, res);
            } else return make_pair(1, res);
        }
        double t = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e));
        res.x += (e.x - s.x) * t;
        res.y += (e.y - s.y) * t;
        return make_pair(2, res);
    }

} l1, l2;

bool inter(L a, L b) {
    return
            max(a.s.x, a.e.x) >= min(b.s.x, b.e.x) &&
            max(b.s.x, b.e.x) >= min(a.s.x, a.e.x) &&
            max(a.s.y, a.e.y) >= min(b.s.y, b.e.y) &&
            max(b.s.y, b.e.y) >= min(a.s.y, a.e.y) &&
            (sgn((a.s - b.e) ^ (b.s - b.e)) * sgn((a.e - b.e) ^ (b.s - b.e)) <= 0) &&
            (sgn((b.s - a.e) ^ (a.s - a.e)) * sgn((b.e - a.e) ^ (a.s - a.e)) <= 0);
}

inline bool zero() {
    if (!inter(l1, l2) || (sgn(l1.s.y - l1.e.y) == 0 || sgn(l2.s.y - l2.e.y) == 0) ||
        (inter(L(P(l1.s.x, 100000), l1.s), l2) || (inter(L(P(l2.s.x, 100000), l2.s), l1))))
        return true;
    return false;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &l1.s.x, &l1.s.y, &l1.e.x, &l1.e.y, &l2.s.x, &l2.s.y, &l2.e.x, &l2.e.y);
        if (sgn(l1.s.y - l1.e.y) < 0) swap(l1.s, l1.e);
        if (sgn(l2.s.y - l2.e.y) < 0) swap(l2.s, l2.e);
        if (zero()) {
            printf("0.00\n");
            continue;
        }
        P a = (l1 & l2).second;
        // 这里并不需要判断线段在哪侧,把两种结果都算出来然后取最小值就好了!NICE.
        P b = (l1 & L(P(100000, l2.s.y), l2.s)).second;
        P c = (l2 & L(P(100000, l1.s.y), l1.s)).second;
        printf("%.2lf\n", min((fabs((b - a) ^ (l2.s - a)) / 2), (fabs((c - a) ^ (l1.s - a)) / 2)));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值