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

猜你喜欢

转载自www.cnblogs.com/Willems/p/12383639.html