POJ 2826 (求线段交点 + 思维)
题目:传送门
题意:给你两条线段,问你这两条线段能接多少雨水,雨水从 y 轴正半轴往 y 轴负半轴垂直滴。
思路:有多种情况,讨论一下即可。
1、若有一条线段与 x 轴平行,那肯定接不了水。
2、若两条线段不相交, 也接不了水。
3、接口被遮住了,也不接不了水
第三种情况的判断可以通过,判断线段的上端点向 y 轴正半轴的射线是否与 另一条线段相交,相交则接口被遮住。
此代码C++能过,G++过不了
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> #include <map> #include <vector> #include <set> #include <string> #include <math.h> #define LL long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF 1e20 #define inf LLONG_MAX #define PI acos(-1) using namespace std; const int N = 55; const double eps = 1e-8; struct Point { double x, y; Point(double x = 0, double y = 0) : x(x), y(y) { } }; int dcmp(double x) { if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; } Point operator + (Point A, Point B) { return Point(A.x + B.x, A.y + B.y); } Point operator - (Point A, Point B) { return Point(A.x - B.x, A.y - B.y); } Point operator * (Point A, double p) { return Point(A.x * p, A.y * p); } Point operator / (Point A, double p) { return Point(A.x / p, A.y / p); } double Cross(Point A, Point B) { return A.x * B.y - A.y * B.x; } double Dot(Point A, Point B) { return A.x * B.x + A.y * B.y; } inline Point GetLineIntersection(const Point P, const Point v, const Point Q, const Point w) {///求直线p + v*t 和 Q + w*t 的交点,需确保有交点,v和w是方向向量 Point u = P - Q; double t = Cross(w, u) / Cross(v, w); return P + v * t; } inline bool Onsegment(Point p, Point a1, Point a2) { /// 判断点p是否在线段p1p2上 return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) <= 0; } inline bool SegmentProperInsection(Point a1, Point a2, Point b1, Point b2) { /// 判断线段是否相交 if(dcmp(Cross(a1 - a2, b1 - b2)) == 0) /// 两线段平行 return Onsegment(b1, a1, a2) || Onsegment(b2, a1, a2) || Onsegment(a1, b1, b2) || Onsegment(a2, b1, b2); Point tmp = GetLineIntersection(a1, a2 - a1, b1, b2 - b1); return Onsegment(tmp, a1, a2) && Onsegment(tmp, b1, b2); } void solve() { Point A, B, C, D; scanf("%lf %lf %lf %lf", &A.x, &A.y, &B.x, &B.y); scanf("%lf %lf %lf %lf", &C.x, &C.y, &D.x, &D.y); if(dcmp(A.y - B.y) > 0) swap(A, B); if(dcmp(C.y - D.y) > 0) swap(C, D); ///若有线段与 x 轴平行,则接不到水 if(dcmp(C.y - D.y) == 0 || dcmp(A.y - B.y) == 0) { puts("0.00"); return; } /// 若两线段不相交,则接不了水 if(SegmentProperInsection(A, B, C, D) == false) { puts("0.00"); return; } /// 若接口被遮住了也接不了水 if(SegmentProperInsection(A, B, D, Point(D.x, 100000)) || SegmentProperInsection(C, D, B, Point(B.x, 100000))) { puts("0.00"); return; } /// 求面积 Point tmp = GetLineIntersection(A, B - A, C, D - C); Point P1 = Point(100000, B.y), P2 = Point(100000, D.y); Point P = GetLineIntersection(C, D - C, B, P1 - B); double ans1 = fabs(Cross(B - tmp, P - tmp)) / 2.0; P = GetLineIntersection(A, B - A, D, P2 - D); double ans2 = fabs(Cross(D - tmp, P - tmp)) / 2.0; double ans = min(ans1, ans2); printf("%.2f\n", ans); } int main() { int _; scanf("%d", &_); while(_--) solve(); return 0; }
一步一步,永不停息