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