poj 2826 Easy Problem

来源:互联网 发布:后缀io域名 编辑:程序博客网 时间:2024/05/17 22:07

看着题标我就知道肯定要被坑,诶学长推荐的十道几何入门题。。怎么越来越坑了,题目我都没看明白,后面才知道原来求两线段构成个V来接水,但情况好像有点多啊,好多接不到水啊的,还要求交点啊,都不会啊,弱菜只能看着别人的代码,学习怎么去解题,代码好长的感觉,有的甚至上两百行了,要不要这么残暴啊,选了好几份看了思路又学习别人的各种模版巧了代码还是一直WA····,各种坐标x和y弄混,+写成-太是考验了,诶最后硬是撑了一天半整整才算明白。

思路:

1.求两线段构成的槽能装多少雨水,其实就是求相交后那个凹槽面积,不过这里有很多情况。(注:雨水垂直落地的)

情况:1.不相交就肯定不能接水了, 2.相交的话有会有在一条直线上重合的情况这种也不行  3.相交交点刚好为线段端点也不行  4相交后上线段完全遮挡了下线段也不行 

这些都是接不到水的情况

剩下的就是可以接水的了,首先求出交点,然后以两线段中那个向上的Y坐标最小的作为一个端点,在用横线相交求出另外一个交点,最后根据x乘求面积。

这个题细心的地方有很多,而且也包含很多几何常用知识,很好的一个题,收获很大。

#include<stdio.h>#include<stdlib.h>#include<math.h>const double eps=1e-8;struct point{    double x;    double y;}s,d1,d2;;//s交点,d1,d2为由s为端点的剩余三角形的两个点 struct line{    point a;    point b;}line1,line2;int dblcmp(double x){//由于精度问题,这里是一个比较模版     if(fabs(x)<eps)         return 0;     return  x>0.0?1:-1;    }double xmult(point p0,point p1,point p2){ //叉乘     return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);} double dotmult(point p0,point p1,point p2){//点乘,可以很好的判断一个在直线上的点,是否已然在这个直线上的一个线段上     return (p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y); }int judgecross(line L1,line L2){    double s1,s2,s3,s4;    s1=dblcmp(xmult(L1.a,L1.b,L2.a));    s2=dblcmp(xmult(L1.a,L1.b,L2.b));    s3=dblcmp(xmult(L2.a,L2.b,L1.a));    s4=dblcmp(xmult(L2.a,L2.b,L1.b));    if(s1*s2<0&&s3*s4<0)return 1;//常规相交     if(s1==0&&dblcmp(dotmult(L2.a,L1.a,L1.b))<=0)return 1;//非常规相交   这种情况就需要用点成来判断是否只是在直线上而非线段上     if(s2==0&&dblcmp(dotmult(L2.b,L1.a,L1.b))<=0)return 1;    if(s3==0&&dblcmp(dotmult(L1.a,L2.a,L2.b))<=0)return 1;    if(s4==0&&dblcmp(dotmult(L1.b,L2.a,L2.b))<=0)return 1;    return 0;}void getcross(line L1,line L2){//获得交点     s=L1.a;    double t=((L1.a.x-L2.a.x)*(L2.a.y-L2.b.y)-(L1.a.y-L2.a.y)*(L2.a.x-L2.b.x))//这是利用了面积比与线段比的关系由于底相同,就便是边的比              /((L1.a.x-L1.b.x)*(L2.a.y-L2.b.y)-(L1.a.y-L1.b.y)*(L2.a.x-L2.b.x));    s.x+=(L1.b.x-L1.a.x)*fabs(t);//fabs可以去掉,但我不知道为什么可以,这里有向面积符号没有影响么?     s.y+=(L1.b.y-L1.a.y)*fabs(t);}void getpoint(point p1, point p2, double yy){    double dx=p2.x-p1.x;    double dy=p2.y-p1.y;    d1.y=yy;    if(dblcmp(dx)==0)        d1.x=p1.x;    else{        double k=dy/dx;        d1.x=(yy-p1.y)/k+p1.x;    } }  double solve(line L1,line L2){    line L3;//作为一个替代板,和L2的b点相交并且平行于y轴;     if(dblcmp((L1.b.x-L1.a.x)*(L2.b.y-L2.a.y)-(L2.b.x-L2.a.x)*(L1.b.y-L1.a.y))==0)return 0.00;//两条线段重合了     L3.a.x=L3.b.x=L2.b.x;  L3.a.y=L2.b.y;  L3.b.y=L2.b.y+10000.0;     if(judgecross(L1,L3))return 0.00;//被上板覆盖接不到雨水    getcross(L1,L2);//获得交点     if(!dblcmp(s.y-L1.b.y)||!dblcmp(s.y-L2.b.y))return 0.00;//交点刚好是线段端点     getpoint(L1.a,L1.b,L2.b.y);//获得实际高边的三角形端点     d2=L2.b;//因为这是比较矮的那条边已经是三角形的一个顶点     return fabs(xmult(s,d1,d2))/2.0;    }void swp(point &p1,point &p2){    point p;    p.x=p1.x, p.y=p1.y;  p1.x=p2.x, p1.y=p2.y;  p2.x=p.x, p2.y=p.y;}int main(){    int t;    double ans;    scanf("%d",&t);    while(t--){        scanf("%lf %lf %lf %lf",&line1.a.x,&line1.a.y,&line1.b.x,&line1.b.y);        scanf("%lf %lf %lf %lf",&line2.a.x,&line2.a.y,&line2.b.x,&line2.b.y);        if(dblcmp(line1.a.y-line1.b.y)>0)//先把这些点处理一下方便用,这里将每条线段的两个点按照纵坐标从小到大排好             swp(line1.a,line1.b);        if(dblcmp(line2.a.y-line2.b.y)>0)             swp(line2.a,line2.b);        if(dblcmp(line1.b.y-line2.b.y)<0){//这里同样是为了方便后面处理,将y坐标比较高的那条线段列为第一条线段              swp(line1.a,line2.a);             swp(line1.b,line2.b);         }         if(!dblcmp(line1.a.y-line1.b.y)||!dblcmp(line2.a.y-line2.b.y))ans=0.00;//如果有其中一条板是平行的,答案就是0;         else{//不平行那么就属于其他的情况             if(judgecross(line1,line2))ans=solve(line1,line2);              else  ans=0.00;        }         printf("%.2lf\n",ans);    }    return 0;}


原创粉丝点击