POJ 2826 An Easy Problem?!(计算几何)

An Easy Problem?!

Time Limit: 1000MS
Memory Limit: 65536K
Problem Description

It’s raining outside. Farmer Johnson’s bull Ben wants some rain to water his flowers. Ben nails two wooden boards on the wall of his barn. Shown in the pictures below, the two boards on the wall just look like two segments on the plane, as they have the same width.

在这里插入图片描述

Your mission is to calculate how much rain these two boards can collect.
Input

The first line contains the number of test cases.
Each test case consists of 8 integers not exceeding 10,000 by absolute value, x1, y1, x2, y2, x3, y3, x4, y4. (x1, y1), (x2, y2) are the endpoints of one board, and (x3, y3), (x4, y4) are the endpoints of the other one.

Output

For each test case output a single line containing a real number with precision up to two decimal places - the amount of rain collected.

Sample Input

2
0 1 1 0
1 0 2 1

0 1 2 1
1 0 1 2

Sample Output

1.00
0.00

题意

在二维平面上,有两根木条,求当下雨时,能接到水的面积。

题解:

题目的精度要求也不算高,只是需要考虑的特殊情况有点多。
1.无交点的情况
2.有平放的模板
3.有垂直放的模板
4.两根木板有交点,但交点上方的一根木板完全把另一根模板盖住
如 0 0 7 7 0 0 3 1这种数据
考虑完这些特殊情况后,剩下的直接利用斜率算就好了。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-8
 
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 200100;
const int mod = 1e9+7;
struct point{
	double x, y;
	point( ){}
	point( double a, double b):x(a),y(b){}
	point operator +(point b)const{
		return point(x+b.x, y+b.y);
	}
	point operator -(point b)const{
		return point(x-b.x, y-b.y);
	}
	//点积 
	double operator *(point b)const{
		return x*b.x + y*b.y;
	}
	//叉积 
	double operator ^(point b)const{
		return x*b.y-y*b.x;
	}
}p1, p2, p3, p4;
void read(point &p);
int sgn(double x);
int intersect(double l1,double r1,double l2,double r2);
bool IsCom(point a, point b, point c, point d);
double dist(point a, point b);

int main()
{
	int t, i, j, k;
	scanf("%d", &t);
	while(t--)
	{
		read(p1), read(p2);
		read(p3), read(p4);
		//如果不相交或有至少一根木条平放则一定没积水
		if(!IsCom(p1, p2, p3, p4) || sgn(p3.y-p4.y) == 0 || sgn(p1.y-p2.y)==0){
			printf("0.00\n");
			continue;
		}
		//有一根木条竖放,另一根目标不竖放
		if(sgn(p1.x-p2.x) == 0 && sgn(p3.x-p4.x)!=0){
			double k = (p3.y-p4.y)/(p3.x-p4.x);
			double b = p3.y - k * p3.x;
			double cx = p1.x;
			double cy = k*cx+b;
			double my = min(max(p1.y, p2.y), max(p3.y, p4.y));
			double mx = fabs(p1.x - (my-b)/k);
			printf("%.2f\n", mx*(my-cy)*0.5+eps);
		}
		else if(sgn(p1.x-p2.x) != 0 && sgn(p3.x-p4.x)==0){
			double k = (p1.y-p2.y)/(p1.x-p2.x);
			double b = p1.y - k * p1.x;
			double cx = p3.x;
			double cy = k*cx+b;
			double my = min(max(p1.y, p2.y), max(p3.y, p4.y));
			double mx = fabs(p3.x - (my-b)/k);
			printf("%.2f\n", mx*(my-cy)*0.5+eps);
		}
		else if(sgn(p3.x-p4.x)!=0 && sgn(p1.x-p2.x)!=0)
		{
			double k1 = (p1.y-p2.y)/(p1.x-p2.x), k2 = (p3.y-p4.y)/(p3.x-p4.x);
			double b1 = p1.y - p1.x*k1, b2 = p3.y - p3.x*k2;
			//考虑上方的木条完全盖过另一根木条
			if(k1>0 && k2>0 && k1 > k2 && max(p1.x,p2.x) >= max(p3.x,p4.x))
				printf("0.00\n");
			else if(k1>0 && k2>0 && k1 < k2 && max(p1.x,p2.x) <= max(p3.x,p4.x))
				printf("0.00\n");
			else if(k1<0 && k2<0 && k1 > k2 && min(p1.x,p2.x) >= min(p3.x,p4.x))
				printf("0.00\n");
			else if(k1<0 && k2<0 && k1 < k2 && min(p1.x,p2.x) <= min(p3.x,p4.x))
				printf("0.00\n");
			else if(sgn(k1-k2) == 0)
				printf("0.00\n");
			else{
				double cx = (b1-b2)/(k2-k1);
				double cy = cx*k1 + b1;
				double my = min(max(p1.y, p2.y), max(p3.y, p4.y));
				double mx = fabs((my-b1)/k1 - (my-b2)/k2);
				printf("%.2f\n", mx*(my-cy)*0.5+eps);
			}
		}
		else
			printf("0.00\n");
	}
	return 0;
}

void read(point &p)
{
	scanf("%lf %lf", &p.x, &p.y);
}

int sgn(double x)
{
	if(x > eps)return 1;
	else if(x < -eps)return -1;
	else return 0;
}

double dist(point a, point b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}


int intersect(double l1,double r1,double l2,double r2)
{//快速排斥实验
    if (l1>r1) swap(l1,r1); 
	if (l2>r2) swap(l2,r2); 
	return sgn(r1-l2)!=-1&&sgn(r2-l1)!=-1;
}

bool IsCom(point a, point b, point c, point d)
{
	if(!(intersect(a.x, b.x, c.x, d.x) && intersect(a.y, b.y, c.y, d.y)))return false;
	double d1 = (b-c)^(d-c), d2 = (a-c)^(d-c);
	double d3 = (c-a)^(b-a), d4 = (d-a)^(b-a);
	if(sgn(d1*d2)<= 0 && sgn(d3*d4)<=0)
		return true;
	else return false; 
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值