An Easy Problem?! POJ 2826 計算幾何
題目: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)
{
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 - 1556 【計算幾何 + 最短路】
- POJ 2991 Crane(線段樹+計算幾何)
- POJ 1556 The Doors(Dijkstra+計算幾何)
- POJ 1113 Wall(思維 計算幾何 數學)
- 計算幾何
- POJ 1127-Jack Straws(計算幾何 線段相交)
- POJ 1039-Pipe(計算幾何-線段相交、求交點)
- 計算幾何:模板
- 計算幾何模板
- ACM A problem is easyACM
- [筆記] 計算幾何筆記
- 【計算幾何】向量表示
- 【總結】計算幾何模板
- 二維計算幾何模板
- 【計算幾何】線段相交
- 三維計算幾何模板
- Something about 計算幾何
- 計算幾何 —— 二維幾何基礎 —— 距離度量方法
- 邊緣計算、霧計算、雲端計算區別幾何?
- 【學習筆記】計算幾何筆記
- 計算幾何_向量的實現
- 【計算幾何】多邊形交集
- 計算幾何——平面最近點對
- POJ 3335-Rotating Scoreboard(計算幾何-半平面交順時針模板)
- POJ 1584-A Round Peg in a Ground Hole(計算幾何-凸包、點到線段距離)
- 計算幾何常用的函式/方法函式
- POJ 1408-Fishnet(計算幾何-根據交點求多邊形面積)
- 【poj3468】A Simple Problem with Integers
- BNUOJ 12887 isumi(計算幾何+最大流)
- SGU 124 Broken line(計算幾何)
- 【計算幾何】Triangles HUST 1607
- 【計算幾何】多邊形點集排序排序
- POJ 2355 Railway Ticket problemAI
- C++計算幾何演算法大全C++演算法
- 【計算幾何】點在多邊形內部
- POJ 3130-How I Mathematician Wonder What You Are!(計算幾何-星形-半平面交逆時針模板)
- 二維幾何常用運算
- SGU 120 SGU 228 Archipelago(計算幾何)Go