POJ-2826 An Easy Problem?!(一点都不Easy)

An Easy Problem?!

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 16428   Accepted: 2555

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

[Submit]   [Go Back]   [Status]   [Discuss]

扫描二维码关注公众号,回复: 4925206 查看本文章

Home Page   Go Back  To top

题目大意:分别给你两块木板的两个两个端点坐标,现在要下雨了(雨是垂直落下),问你这两个木板能装多少水。

题意就是这,真是So Easy 但是如果真的像题意简单就好了,这道题坑比较多,耗时一天之久,借鉴了各位大佬的讨论,才在判题机的帮助下,勉强过了此题。

注意的点有:(PS:菜鸡想的情况有点多,可能有些复杂,大佬不喜勿喷

第一:两个木板不相交,这肯定无法接到水,输出0

就是这样的:

或这样的:这样的都接不到水

这个比较好想

第二:两个木板相交

1:有一块木板平行于X轴,输出0;

2:有一块木板很长,斜率也很大,遮住了另一块木板。例如这样:

或者这样:

这样挡住了端口,无法接到水

3:当交点是其中一条线段的端点的时候:

<1 和第二种情况一样,可以与其同时考虑

<2交点上面某条线段的端点,形成了倒V形,或”人“形,或"入"形,也无法接到水即

<3如果是V形,或X形,直接计算

4:木桶原理,当两条线段的两个端点的y值不同时,取决于最小的那个端点的y值,大概是这个样子:

最后要注意精度,还有要用叉积来计算三点围成的面积,不然误差可能会比较大

代码:C++

/*
给你两条线段,让你判断这个线段能接到多少水(判断容积)
思路:
1:两直线如果不相交输出0
2:相交时:
<1若有一条线段平行于x输出0
<2若一条直线很长,遮住了另一条直线,输出0
<3并且还要考虑端点问题,当交点是一个端点时
  <1 V形直接计算
  <2 端点在另一条线段上形状为:入,人
  <3算出交点,判断交点的位置,如果交点像倒V一样,无法接水输出0
<4还要考虑相交但是其中一条边的端点位置低于另一条,木桶原理,容积取决于最短的那个木
最后计算三个点围成的三角形面积S = |(x1-x3)*(y2-y3)-(x2-x3)*(y1-y3)|/2
*/
#include<map>
#include<stack>
#include<queue>
#include<string>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define ul unsigned long long
#define bug printf("mmp\n");
#define inf 0x3f3f3f3f
#define esp 1e-8
#define mm(a,b) memset(a,b,sizeof(a))
#define T()int test,q=1,tt;scanf("%d",&test),tt=test;while(test--)
const int N=1e3+10;
const int maxn=1e6+100;
const int mod=1000000007;
struct point
{
    double x,y;
};
struct line
{
    point st,ed;
    double k,b;///线段的斜率和截距
};
int sign(double x)
{
    if(fabs(x)<esp)
        return 0;
    return x>0?1:-1;
}
double mult(point a,point b,point c)///叉积
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
double dis(point a,point b)///两个点的距离
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int judge(line l1,line l2)///判断两条线是否相交,且如何相交
{
    int a1=sign(max(l1.st.x,l1.ed.x)-min(l2.st.x,l2.ed.x));
    int a2=sign(max(l2.st.x,l2.ed.x)-min(l1.st.x,l1.ed.x));
    int a3=sign(max(l1.st.y,l1.ed.y)-min(l2.st.y,l2.ed.y));
    int a4=sign(max(l2.st.y,l2.ed.y)-min(l1.st.y,l1.ed.y));
    int a5=sign(mult(l2.st,l1.st,l2.ed));
    int a6=sign(mult(l2.st,l1.ed,l2.ed));
    int a7=sign(mult(l1.st,l2.st,l1.ed));
    int a8=sign(mult(l1.st,l2.ed,l1.ed));
    if(a1>=0&&a2>=0&&a3>=0&&a4>=0)
    {
        if(!a5&&!a6)
            return 1;///两线同一条线
        if(a5*a6>0||a7*a8>0)
            return 0;///不相交
        if(!a5||!a6||!a7||!a8)
            return 2;///交点为一个端点
        return 3;///普通相交
    }
    return 0;
}
double ck(line l)///计算斜率
{
    if(l.st.x==l.ed.x)
        return 0;
    return ((l.st.y-l.ed.y)/(l.st.x-l.ed.x));
}
point maxs(point a,point b)///返回y值较大的
{
    if(a.y>b.y)
        return a;
    return b;
}
point jiaod(line l1,line l2)///计算交点
{
    point jiao;
    double A1=l1.ed.y-l1.st.y;
    double B1=l1.st.x-l1.ed.x;
    double C1=(l1.ed.x-l1.st.x)*l1.st.y-(l1.ed.y-l1.st.y)*l1.st.x;
    double A2=l2.ed.y-l2.st.y;
    double B2=l2.st.x-l2.ed.x;
    double C2=(l2.ed.x-l2.st.x)*l2.st.y-(l2.ed.y-l2.st.y)*l2.st.x;
    jiao.x=(C2*B1-C1*B2)/(A1*B2-A2*B1);
    jiao.y=(C1*A2-C2*A1)/(A1*B2-A2*B1);
    return jiao;
}
double cs(point a,point b,point c)///计算三个点围成的面积
{
    if(!sign(a.x-b.x)&&!sign(a.y-b.y)||!sign(a.x-c.x)&&!sign(a.y-c.y))///倒V为0
        return 0;
    point bb;
    ///木桶原理
    if(sign(b.y-c.y)>=0)
    {
        bb.y=c.y;
        bb.x=a.x+(b.x-a.x)*(c.y-a.y)/(b.y-a.y);///将点代入另一条线段求其对应点
        return fabs(mult(a,c,bb))*0.5;
    }
    else
    {
        bb.y=b.y;
        bb.x=a.x+(c.x-a.x)*(b.y-a.y)/(c.y-a.y);
        return fabs(mult(a,b,bb))*0.5;
    }
}
int main()
{
    T()
    {
        line l1,l2;
        point ma,mb,jiao;
        double ans=0;
        cin>>l1.st.x>>l1.st.y>>l1.ed.x>>l1.ed.y;
        cin>>l2.st.x>>l2.st.y>>l2.ed.x>>l2.ed.y;
        int flag=judge(l1,l2);
        if(flag<=1)///当两线不相交或同线时
            ans=0;
        else
        {
            if((l1.st.y==l1.ed.y)||(l2.st.y==l2.ed.y))///当其中有一条线段平行于x轴时
                ans=0;
            else
            {///找到y值较大的点和两条线的斜率
                l1.k=ck(l1),ma=maxs(l1.st,l1.ed);
                l2.k=ck(l2),mb=maxs(l2.st,l2.ed);
                jiao=jiaod(l1,l2);///求其交点
                if(sign(l1.k*l2.k)>0)///当同号的时候
                {
                    ///覆盖情况
                    int jk=sign(l1.k-l2.k);///判断直线关系
                    int jl=sign(l1.k);
                    int jp1=sign(mb.x-ma.x)*sign(mb.x-jiao.x);
                    int jp2=sign(ma.x-mb.x)*sign(ma.x-jiao.x);
                    if(jk>0&&jl>0&&jp1<=0||(jk<0&&jl>0&&jp2<=0)||
                            (jk>0&&jl<0&&jp2<=0)||(jk<0&&jl<0&&jp1<=0))
                        ans=0;
                    ///未覆盖
                    else
                        ans=cs(jiao,ma,mb);
                }
                else///两条线段交叉相交,可直接计算其面积
                    ans=cs(jiao,ma,mb);
            }
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

另外再给些大佬们测试的数据:

输入:
7
6259 2664 8292 9080
1244 2972 9097 9680

0 1 1 0
1 0 2 1

0 1 2 1
1 0 1 2
0 0 10 10
0 0 9 8

0 0 10 10
0 0 8 9

0.9 3.1 4 0
0 3 2 2
0 0 0 2
0 0 -3 2

1 1 1 4
0 0 2 3

1 2 1 4
0 0 2 3
输出:
6162.65

1.00

0.00

0.00

4.50

0.50

3.00

0.75

0.00

猜你喜欢

转载自blog.csdn.net/lee371042/article/details/86489366