An Easy Problem?!
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.
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;
}