An Easy Problem?! POJ 2826 计算几何
2017-11-13 17:25
453 查看
题目:https://cn.vjudge.net/problem/POJ-2826
题意:二维平面上,给出两条线段,雨水竖直下落,问由这两条线段组成的容器能盛多少水(面积)。
思路:一句话就描述完的题意,看似简单,却情况繁多,想AC一点不容易。
这题的具体做法很灵活,以下是我的方法,未必是最佳做法。
先说一下有解情况下的面积计算方法:
如图:
![](https://img-blog.csdn.net/20171113165841637?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvUmV3cml0ZXJfaHVhbnlpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
AB CD两线段交点为O,从过C点引平行线交AB与E,三角形COE即为所求。
ans = 0.5 * CE * (yc - yo)
对各种情况的分类:
(由于判断条件不互相独立,需按以下顺序判断,否则未必正确,会有奇奇怪怪的情况漏掉)
(1)若两条线段只要有一条水平,或者这两条线段平行or重合,ans = 0;
![](https://img-blog.csdn.net/20171113164751479?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvUmV3cml0ZXJfaHVhbnlpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(2)若有任意一条线段的较高点在另一条线段上,ans = 0;
![](https://img-blog.csdn.net/20171113164601800?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvUmV3cml0ZXJfaHVhbnlpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(3)两条线段不相交,ans = 0。
(4)若有一条线竖直,或两条线段斜率异号,则必定有解,按上文所述方法计算。
![](https://img-blog.csdn.net/20171113170649710?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvUmV3cml0ZXJfaHVhbnlpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(5)剩下最麻烦的情况了
余下的只剩斜率同号的情况,在上面的线段有可能会遮挡下面的线段导致水进不去容器。
5.1被遮挡
![](https://img-blog.csdn.net/20171113171149700?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvUmV3cml0ZXJfaHVhbnlpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
5.2不被遮挡
![](https://img-blog.csdn.net/20171113171408217?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvUmV3cml0ZXJfaHVhbnlpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
考虑如何判断是否被遮挡
![](https://img-blog.csdn.net/20171113171935796?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvUmV3cml0ZXJfaHVhbnlpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
首先,考虑谁遮挡谁——斜率绝对值大的线段遮挡斜率绝对值小的线段。
然后,怎么样算遮挡——abs(Xa - Xo) >= abs (Xb - Xo)时,构成遮挡。
总算写完了(╯°Д°)╯︵ ┻━┻
还有个细节,这题输出的时候需要加个eps以防保留两位四舍五入的时候出错。
代码:
题意:二维平面上,给出两条线段,雨水竖直下落,问由这两条线段组成的容器能盛多少水(面积)。
思路:一句话就描述完的题意,看似简单,却情况繁多,想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; }
相关文章推荐
- poj 2826 An Easy Problem?!(计算几何)
- POJ 2826 An Easy Problem?!(计算几何)
- POJ 2826 An Easy Problem?! (计算几何、线段相交、思维)
- POJ 2826 An Easy Problem 计算几何
- POJ 2826 An Easy Problem?!(计算几何)
- POJ 2826 An Easy Problem?! --计算几何,叉积
- poj-2826 An Easy Problem?!(计算几何,好题)
- 计算几何 POJ 2826 An Easy Problem?! (线段位置判断并且求交点)
- POJ 2826 An Easy Problem?! <计算几何>
- 【POJ 2826】An Easy Problem?!(几何、线段)
- POJ 2826 An easy problem?! 几何基础
- An Easy Problem?! POJ - 2826 (几何)
- 简单几何(线段相交) POJ 2826 An Easy Problem?!
- POJ 2826 An Easy Problem?!(线段交点+简单计算)
- POJ 2826 An Easy Problem?! (线段相交)
- POJ 2826 An Easy Problem?![线段]
- POJ 2826 An Easy Problem?!
- poj 2826 An Easy Problem?!(线段交,细节题)
- Poj 2826 An Easy Problem?!
- POJ 2826 An Easy Problem?!