题目链接: http://acm.pku.edu.cn/JudgeOnline/problem?id=2826

大致意思是给你两条线段,问组成的开口向上的V形区域能盛多少雨水。雨水是垂直落下的。

显然线段不相交,或者平行,重合,或者有一条斜率为0时结果为0.00

然后还有一种情况结果为0的,就是高的那条线段被低的挡住了。

判断覆盖可以从最高点较低的线段的最高点引一条向y轴正向的线段,线段最高点坐标大于10000(题目说的坐标绝对值不大于10000),然后判断线段是否和原来两条线段都相交,是则输出0.00

最后还要注意精度,我是结果加上eps才过的,面积计算使用的是海伦公式。

提供几组数据

Input:

0 0 100 100
0 0 100 99

0 0 100 100
0 0 101 99

0 0 1 1
0 0 2 2

0 0 -100 100
0 0 100 99

0 0 1 1
1 1 2 2

Output:

0.00

99.00

0.00

9850.50

0.00

代码如下:

#include <iostream>
#include <cstdio>
#include <cmath>

const double eps = 1e-8;
struct point
{
    int x, y;

    point(){}
    point(int _x, int _y):x(_x),y(_y){};

    static int xmult(const point &p1, const point &p2, const point & p0)
    {
        return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
    }
    bool operator > (const point &_p) const
    {
        return y > _p.y;
    }
};

struct segment
{
    point s, e;

    segment(){}
    segment(const point &_s, const point &_e):s(_s),e(_e){}

    double operator *(const segment &_Off) const
    {
        return (e.x - s.x) * (_Off.e.y - _Off.s.y) - (e.y - s.y) * (_Off.e.x - _Off.s.x);
    }
    bool cross(const segment &_Off) const
    {
        return (
            (std::max(s.x, e.x) >= std::min(_Off.s.x, _Off.e.x)) &&
            (std::max(_Off.s.x, _Off.e.x) >= std::min(s.x, e.x)) &&
            (std::max(s.y, e.y) >= std::min(_Off.s.y, _Off.e.y)) &&
            (std::max(_Off.s.y, _Off.e.y) >= std::min(s.y, e.y)) &&
            ((segment(_Off.s, s) * _Off) * (_Off * segment(_Off.s, e)) >= 0.0) &&
            ((segment(s, _Off.s) * (*this)) * ((*this) * segment(s, _Off.e)) >= 0.0)
            );
    }

    bool par(const segment &_s) const
    {
        return (e.y - s.y) * (_s.e.x - _s.s.x) - (e.x - s.x) * (_s.e.y - _s.s.y) == 0;
    }

    bool her()
    {
        return s.y == e.y;
    }
};

std::pair<double, double> cross(const segment &a, const segment &b)
{
    double a1 = a.s.y - a.e.y;
    double b1 = a.e.x - a.s.x;
    double c1 = a.s.x * a.e.y - a.e.x * a.s.y;
    double a2 = b.s.y - b.e.y;
    double b2 = b.e.x - b.s.x;
    double c2 = b.s.x * b.e.y - b.e.x * b.s.y;
    return std::make_pair((c1 * b2 - c2 * b1) / (a2 * b1 - a1 * b2)
            , (c1 * a2 - c2 * a1) / (b2 * a1 - b1 * a2));
}

double dis(std::pair<double, double> a, std::pair<double, double> b)
{
    return std::sqrt((a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second));
}
double area(double a, double b, double c)
{
    double s = (a + b + c) / 2;
    return std::sqrt(s * (s - a) * (s - b) * (s - c));
}
std::pair<double, double> getpt(std::pair<double, double> x, const point &pt, double y)
{
    double py = pt.y - x.second;
    double px = pt.x - x.first;
    if(std::fabs(py) < eps)
        return x;
    return std::make_pair(x.first + (y - x.second) * px / py, y);
}

int main()
{
    segment a, b;
    point ap, bp, mxp, mnp;
    int i, t;
    std::scanf("%d", &t);
    while(t --)
    {
        std::scanf("%d %d %d %d %d %d %d %d"
            , &a.s.x, &a.s.y, &a.e.x, &a.e.y
            , &b.s.x, &b.s.y, &b.e.x, &b.e.y);
        if(a.her() || b.her() || a.cross(b) == false || a.par(b))
        {
            std::printf("0.00\n");
            continue;
        }
        ap = (a.s > a.e)? a.s: a.e;
        bp = (b.s > b.e)? b.s: b.e;

        std::pair<double, double> pt1, pt2, pt0 = ::cross(a, b);

        if((ap.x - pt0.first) * (bp.x - pt0.first) > eps)
        {
            mnp = (ap > bp)?bp: ap;
            if(segment(mnp, point(mnp.x, 30000)).cross(a) && segment(mnp, point(mnp.x, 30000)).cross(b))
            {
                std::printf("0.00\n");
                continue;
            }
        }

        if(ap > bp)
        {
            pt1 = std::make_pair(bp.x, bp.y);
            pt2 = ::getpt(pt0, ap, pt1.second);
        }
        else
        {
            pt1 = std::make_pair(ap.x, ap.y);
            pt2 = ::getpt(pt0, bp, pt1.second);
        }

        std::printf("%.2lf\n", ::area(::dis(pt0, pt1), ::dis(pt0, pt2), ::dis(pt2, pt1)) + eps);
    }
    return 0;
}