Poj 2826

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
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值