POJ - 2826 An Easy Problem?!(计算几何 + 思维)

链接 An Easy Problem?!

题意

两个木板,问能接多少雨水;

思路

考虑多种情况:

  • 不相交
  • 一个木板与x轴平行
  • 长木板挡住接水

第三种情况大概是这样的

在这里插入图片描述
情况都考虑周全即可;

AC代码

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>

using namespace std;

const double eps = 1e-8;
const int N = 10010;

int sign(double x)
{
	if (fabs(x) < eps) return 0;
	if (x < 0) return -1;
	return 1;
}

struct Point
{
	double x, y;
	Point(){}
	Point(double _x, double _y)
	{
		x = _x, y = _y;
	}
	Point operator -(const Point &a) const
	{
		return Point(x - a.x, y - a.y);
	}
	//叉积
	double operator ^(const Point &a) const
	{
		return x * a.y - y * a.x;
	}
	//点积
	double operator *(const Point &a) const
	{
		return x * a.x + y * a.y;
	}
};

struct Line
{
	Point st, ed;
	Line(){}
	Line(Point _st, Point _ed)
	{
		st = _st, ed = _ed;
	}

	//两直线相交求交点
	//只有第一个值为2时,交点才有意义;
	pair<int, Point> operator &(const Line &a) const
	{
		Point res = st;
		if (sign((st - ed) ^ (a.st - a.ed)) == 0)
		{
			//重合
			if (sign((st - a.ed) ^ (a.st - a.ed)) == 0) return make_pair(0, res);

			//平行
			return make_pair(1, res);
		}

		double t = ((st - a.st) ^ (a.st - a.ed)) / ((st - ed) ^ (a.st - a.ed));
		res.x += (ed.x - st.x) * t;
		res.y += (ed.y - st.y) * t;
		//求交点
		return make_pair(2, res);
	}
};

bool intersect(Line a, Line b)
{
	return
	max(a.st.x, a.ed.x) >= min(b.st.x, b.ed.x) &&
	max(b.st.x, b.ed.x) >= min(a.st.x, a.ed.x) &&
	max(a.st.y, a.ed.y) >= min(b.st.y, b.ed.y) &&
	max(b.st.y, b.ed.y) >= min(a.st.y, a.ed.y) &&
	sign((b.st - a.ed) ^ (a.st - a.ed)) * sign((b.ed - a.ed) ^ (a.st - a.ed)) <= 0 &&
	sign((a.st - b.ed) ^ (b.st - b.ed)) * sign((a.ed - b.ed) ^ (b.st - b.ed)) <= 0;
}

bool judge(Line a, Line b)
{
	//平行于x轴
	if (sign(a.st.y - a.ed.y) == 0 || sign(b.st.y - b.ed.y) == 0) return true;
	//不相交
	if (!intersect(a, b)) return true;

	//口被封上
	if (intersect(Line(a.st, Point(a.st.x, 10000000)), b) || intersect(Line(b.st, Point(b.st.x, 10000000)), a)) return true;
}

void solve(Line a, Line b)
{
	pair<int, Point> pr;
	pr = a & b;
	Point p = pr.second;
	double ans1;
	pr = b & Line(Point(10000000, a.st.y), a.st);
	Point p1 = pr.second;
	ans1 = fabs((a.st - p) ^ (p1 - p)) / 2;
	double ans2;
	pr = a & Line(Point(10000000, b.st.y), b.st);
	Point pw = pr.second;
	ans2 = fabs((b.st - p) ^ (pw - p)) / 2;
	printf("%.2lf\n", min(ans1, ans2) + eps);

}

int main()
{
	int T;
	cin >> T;

	while (T --)
	{
		int x1, y_1, x2, y2, x3, y3, x4, y4;
		cin >> x1 >> y_1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4;

		Line l1, l2;
		l1 = Line(Point(x1 ,y_1), Point(x2, y2));
		l2 = Line(Point(x3, y3), Point(x4, y4));


		if (sign(l1.st.y - l1.ed.y) < 0) swap(l1.st, l1.ed);
		if (sign(l2.st.y - l2.ed.y) < 0) swap(l2.st, l2.ed);
		if (judge(l1, l2)) printf("0.00\n");
		else solve(l1, l2);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半碗无糖蓝莓冻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值