An Easy Problem?!
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 7837 | Accepted: 1145 |
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
Source
POJ Monthly--2006.04.28, Dagger@PKU_RPWT
需要想到好几种特殊情况。
线段不相交,结果为0.
有一条线段平行于x轴结果也为0;
尤其是第三种情况,很难想到。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
struct point{
double x,y;
point(){}
point(double _x,double _y)
{
x=_x;y=_y;
}
};
struct LINE{
point a,b;
LINE(){}
LINE(point _a,point _b){
a=_a;b=_b;
}
};
point operator + (point A, point B) { return point(A.x + B.x, A.y + B.y); }
point operator - (point A, point B) { return point(A.x - B.x, A.y - B.y); }
point operator * (point A, double p) { return point(A.x * p, A.y * p); }
point operator / (point A, double p) { return point(A.x/p, A.y/p); }
bool operator < (const point& a, const point& b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
const double eps = 1e-8;
int dcmp(double x) {
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
bool operator == (const point& a, const point& b) {
return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
double Dot(point A, point B) { return A.x * B.x + A.y * B.y; } //点积
double Cross(point A, point B) { return A.x * B.y - A.y * B.x; } //叉积
point Getlinenode(point P, point v, point Q, point w) { //两直线交点(点,向量,点,向量)
// printf("w.x=%f,w.y=%f\n",w.x,w.y);
point u = P - Q;
double t = Cross(w, u) / Cross(v, w);
return P + v * t;
}
bool seg_seg_Cross(point s1,point e1,point s2,point e2)//判断两线段是否相交(不包括端点)
{
///第一步,快速排斥实验
if(!(min(s1.x,e1.x)<=max(s2.x,e2.x)&&min(s2.x,e2.x)<=max(s1.x,e1.x)&&
min(s1.y,e1.y)<=max(s2.y,e2.y)&&min(s2.y,e2.y)<=max(s1.y,e1.y))) return false;
double c1=Cross(s2-s1,e1-s1),c2=Cross(e1-s1,e2-s1);
double c3=Cross(s1-s2,e2-s2),c4=Cross(e2-s2,e1-s2);
if(dcmp(c1*c2)>=0&&dcmp(c3*c4)>=0) return 1;
return 0;
}
bool line_seg_Cross(point s1,point e1,point s2,point e2) //判断直线与线段相交,s1e1表示直线,s2e2表示线段
{
double c1=Cross(s2-s1,e1-s1),c2=Cross(e1-s1,e2-s1);
//==0表示,相交于端点也认定为相交
if(dcmp(c1*c2)>=0) return true;
return false;
}
int main()
{
int ncase;
double x1,y1,x2,y2,x3,y3,x4,y4;
scanf("%d",&ncase);
LINE l1,l2;
while(ncase--)
{
scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);
l1=LINE(point(x1,y1),point(x2,y2));
l2=LINE(point(x3,y3),point(x4,y4));
if(dcmp(y1-y2)==0||dcmp(y3-y4)==0){ //某一个木板与地面平行
printf("0.00\n");continue;
}
if(dcmp(y1-y2)<0) swap(l1.a,l1.b);
if(dcmp(y3-y4)<0) swap(l2.a,l2.b);
if(seg_seg_Cross(l1.a,l1.b,l2.a,l2.b)==0){ //两木板没有交点
printf("0.00\n");continue;
}
if(dcmp(Cross(l1.a-l1.b,l2.a-l2.b))==0){ //两木板平行或重合
printf("0.00\n");continue;
}
//口被l2封掉
if(seg_seg_Cross(l1.a,point(l1.a.x,100000),l2.a,l2.b)){
printf("0.00\n");continue;
}
//口被l1封掉
if(seg_seg_Cross(l2.a,point(l2.a.x,100000),l1.a,l1.b)){
printf("0.00\n");continue;
}
//求面积了
point p=Getlinenode(l1.a,l1.a-l1.b,l2.a,l2.a-l2.b); //求两木板的交点
//求过l1.a点并与地面平行的直线和直线l2的交点
point p1=Getlinenode(point(100000,l1.a.y),l1.a-point(100000,l1.a.y),l2.a,l2.b-l2.a);
double ans1=fabs(Cross(p1-p,l1.a-p))/2.0;
p1=Getlinenode(point(100000,l2.a.y),l2.a-point(100000,l2.a.y),l1.a,l1.b-l1.a);
double ans2=fabs(Cross(p1-p,l2.a-p))/2.0;
if(dcmp(ans1-ans2)<0) printf("%.2f\n",ans1+eps); //这里加个eps
else printf("%.2f\n",ans2+eps);
}
return 0;
}
/*
10
0 5 3 0
1 1 3 0
3 0 6 3
3 0 5 1
3 0 6 3
3 0 7 3
0 1 1 0
1 0 2 1
0 1 2 1
1 0 1 2
0 5 3 0
2 5 3 0
*/