[POJ2826]An Easy Problem?!(计算几何)

来源:互联网 发布:网络情缘一线牵表情包 编辑:程序博客网 时间:2024/05/27 01:26

=== ===

这里放传送门

=== ===

题解

这题特判的情况比较多。。首先应该判断这两个线段是不是有且仅有一个焦点。不相交或者重合的情况都是应该出0的。然后就是分情况讨论了,可以发现如果这两个线段的斜率一个大于0一个小于0,它们一定是能接到雨水的,否则要判断从上面竖直落下来的雨水能否打到下面的线段上。一开始用的方法是从上面那条线段的一个端点引了一条竖直向下的直线看有没有交点,但是如果这两个东西的端点是恰好对齐的,实际上也是接不到雨水的但是它会在端点处有一个交点。实际上直接判横坐标大小关系就可以了。
最后就是对于能接到雨水的情况算能接到多少,就是从两条线段的上端点引平行于x轴的直线看是否与另一条相交,求出交点以后算三角形面积就可以了。
这个题精度非常恶心,有可能出现-0.00这样的东西,输出的时候要加个eps。然后就是如果G++不行的话拿C++交。。。

代码

#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const double eps=1e-8;const double inf=1e7;int T;struct Vector{    double x,y;    Vector(double X=0,double Y=0){x=X;y=Y;}    Vector operator + (const Vector &a){return Vector(x+a.x,y+a.y);}    Vector operator - (const Vector &a){return Vector(x-a.x,y-a.y);}    double operator * (const Vector &a){return x*a.y-y*a.x;}    Vector mul(double t){return Vector(x*t,y*t);}    void read(){scanf("%lf%lf",&x,&y);} };struct Line{    Vector P,v,p[2];    double k;    Line(){P=Vector();v=Vector();p[0]=p[1]=Vector();}    void get(){        p[0].read();p[1].read();        if (p[1].y-p[0].y>eps) swap(p[0],p[1]);        P=p[0];v=p[1]-p[0];        if (fabs(v.x)<eps) k=inf;        else k=v.y/v.x;    }//P存储靠上的那个端点     void rev(){        p[0].x=-p[0].x;p[1].x=-p[1].x;        P=p[0];v=p[1]-p[0];        if (fabs(v.x)<eps) k=inf;        else k=v.y/v.x;    }}l1,l2;bool Ins(Line l1,Line l2){    Vector a1,a2,b1,b2,t1,t2;    if (fabs(l1.v*l2.v)<eps) return false;//特判平行的情况     a1=l1.P;a2=a1+l1.v;b1=l2.P;b2=b1+l2.v;    if (min(a1.x,a2.x)>max(b1.x,b2.x)||min(b1.x,b2.x)>max(a1.x,a2.x)) return false;    if (min(a1.y,a2.y)>max(b1.y,b2.y)||min(b1.y,b2.y)>max(a1.y,a2.y)) return false;    t1=a1-b1;t2=a2-b1;    if ((t1*l2.v)*(t2*l2.v)>eps) return false;    t1=b1-a1;t2=b2-a1;    if ((t1*l1.v)*(t2*l1.v)>eps) return false;    return true;}Vector GLI(Line a,Line b){    Vector u=a.P-b.P;    double t=(b.v*u)/(a.v*b.v);    return a.P+a.v.mul(t);}bool check(){return l2.P.x-l1.P.x>eps;}double Calc(){     Line tmp;    Vector i1,i2;    tmp.P=l1.P;tmp.v=Vector(inf,0);//引出平行于x轴的直线    if (Ins(tmp,l2)){        i1=GLI(tmp,l2);i2=GLI(l1,l2);        return fabs((l1.P-i1)*(i2-i1)/2);    }    tmp.P=l2.P;tmp.v=Vector(-inf,0);    if (Ins(tmp,l1)){        i1=GLI(tmp,l1);i2=GLI(l1,l2);        return fabs((l2.P-i1)*(i2-i1)/2);    }    return 0;}int main(){    scanf("%d",&T);    for (int wer=1;wer<=T;wer++){        l1.get();l2.get();        if (!Ins(l1,l2)){printf("0.00\n");continue;}        if (l1.k*l2.k<-eps){            if (l1.k>l2.k) swap(l1,l2);            printf("%.2lf\n",Calc());            continue;        }        if (l1.k<-eps){l1.rev();l2.rev();}        if (l1.k<l2.k) swap(l1,l2);        if (!check()) printf("0.00\n");        else printf("%.2lf\n",Calc());    }    return 0;}

偏偏在最后出现的补充说明

在此郑重感谢cloverhxy和zyf2000用无数的WA挖出了这道题的所有坑点(手动滑稽
这里写图片描述

原创粉丝点击