您的位置:首页 > 其它

An Easy Problem?! POJ 2826 计算几何

2017-11-13 17:25 453 查看
题目https://cn.vjudge.net/problem/POJ-2826

题意:二维平面上,给出两条线段,雨水竖直下落,问由这两条线段组成的容器能盛多少水(面积)。

思路:一句话就描述完的题意,看似简单,却情况繁多,想AC一点不容易。

这题的具体做法很灵活,以下是我的方法,未必是最佳做法。

先说一下有解情况下的面积计算方法:

如图:



AB CD两线段交点为O,从过C点引平行线交AB与E,三角形COE即为所求。

ans = 0.5 * CE * (yc - yo)

对各种情况的分类:

(由于判断条件不互相独立,需按以下顺序判断,否则未必正确,会有奇奇怪怪的情况漏掉)

(1)若两条线段只要有一条水平,或者这两条线段平行or重合,ans = 0;



(2)若有任意一条线段的较高点在另一条线段上,ans = 0;



(3)两条线段不相交,ans = 0。

(4)若有一条线竖直,或两条线段斜率异号,则必定有解,按上文所述方法计算。



(5)剩下最麻烦的情况了

余下的只剩斜率同号的情况,在上面的线段有可能会遮挡下面的线段导致水进不去容器。

5.1被遮挡



5.2不被遮挡



考虑如何判断是否被遮挡



首先,考虑谁遮挡谁——斜率绝对值大的线段遮挡斜率绝对值小的线段。

然后,怎么样算遮挡——abs(Xa - Xo) >= abs (Xb - Xo)时,构成遮挡。

总算写完了(╯°Д°)╯︵ ┻━┻

还有个细节,这题输出的时候需要加个eps以防保留两位四舍五入的时候出错。

代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
using namespace std;

const double eps = 1e-8;

int dcmp(double a)
{
if (fabs(a) < eps)
{
return 0;
}
return a > 0 ? 1 : -1;
}

#define Point Vector

struct Point
{
double x, y;
Point() : x(0), y(0) {}
Point(double xx, double yy) : x(xx), y(yy) {}
bool operator == (const Point &t)
{
return dcmp(x - t.x) == 0 && dcmp(y - t.y) == 0;
}

int ishigher(const Point &t)
{
return dcmp(y - t.y);
}

void input()
{
scanf("%lf%lf", &x, &y);
}
};

Vector operator - (Point A, Point B)
{
return Vector(A.x - B.x, A.y - B.y);
}

Vector operator + (Point A, Point B)
{
return Vector(A.x + B.x, A.y + B.y);
}

double Dot(Vector A, Vector B)
{
return A.x * B.x + A.y * B.y;
}

double Cross(Vector A, Vector B)
{
return A.x * B.y - A.y * B.x;
}

struct Line
{
Point top, bottom;
bool level;//线段水平
bool verticle;//线段竖直
double k;//斜率
Line() {}
Line(Point A, Point B) : top(A), bottom(B), level(false), verticle(false)
{
if (A.ishigher(B) < 0)
{
swap(top, bottom);
}
if (dcmp(top.y - bottom.y) == 0)
{
level = true;
return;
}
if (dcmp(top.x - bottom.x) == 0)
{
verticle = true;
return;
}
k = (top.y - bottom.y) / (top.x - bottom.x);
}

Vector getVector()
{
return bottom - top;
}
};

bool OnSegment(Point P, Line L)
{
return dcmp(Cross(L.top - P, L.bottom - P)) == 0 && dcmp(Dot(L.top - P, L.bottom - P)) <= 0;
}

bool SegmentTerminalIntersection(Line l1, Line l2)
{
return OnSegment(l1.top, l2) || OnSegment(l1.bottom, l2) || OnSegment(l2.top, l1) || OnSegment(l2.bottom, l1);
}

bool SegmentProperIntersection(Line l1, Line l2)
{
if (SegmentTerminalIntersection(l1, l2))
{
return true;
}
double c1 = Cross(l1.getVector(), l2.top - l1.top);
double c2 = Cross(l1.getVector(), l2.bottom - l1.top);
double c3 = Cross(l2.getVector(), l1.top - l2.top);
double c4 = Cross(l2.getVector(), l1.bottom - l2.top);
return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}

Point GetLineIntersection(Point p1, Vector v1, Point p2, Vector v2)
{
Vector u = p1 - p2;
double t1 = Cross(v2, u) / Cross(v1, v2);
return p1 + Vector(v1.x * t1, v1.y * t1);
}

Line l1, l2;
Point O;

double getArea()
{
if (l1.top.ishigher(l2.top) < 0)
{
swap(l1, l2);
}
double height = l2.top.y - O.y;
Point intersection = GetLineIntersection(l2.top, Vector(1, 0), l1.top, l1.getVector());
double bottom = fabs(l2.top.x - intersection.x);
return 0.5 * bottom * height;
}

int main()
{
int T;
cin >> T;
while (T--)
{
Point p[4];
for (int i = 0; i < 4; i++)
{
p[i].input();
}
l1 = Line(p[0], p[1]);
l2 = Line(p[2], p[3]);
if (l1.top.ishigher(l2.top) < 0)
{

a94d
swap(l1, l2);
}
double ans = -1;
if (l1.level || l2.level || dcmp(Cross(l1.getVector(), l2.getVector())) == 0)
{
ans = 0;
}
else if (OnSegment(l1.top, l2) || OnSegment(l2.top, l1))
{
ans = 0;
}
if (ans == -1)
{
O = GetLineIntersection(l1.top, l1.getVector(), l2.top, l2.getVector());
if (!SegmentProperIntersection(l1, l2))
{
ans = 0;
}
else if (l1.verticle || l2.verticle || dcmp(l1.k) * dcmp(l2.k) < 0)
{
ans = getArea();
}
if (ans == -1)
{
if (dcmp(fabs(l1.k) - fabs(l2.k)) > 0)
{
swap(l1, l2);
}
if (dcmp(fabs(l1.top.x - O.x) - fabs(l2.top.x - O.x)) > 0)
{
ans = getArea();
}
else
{
ans = 0;
}
}
}
printf("%.2f\n", ans + eps);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: