poj 2826 Easy Problem

看着题标我就知道肯定要被坑,诶学长推荐的十道几何入门题。。怎么越来越坑了,题目我都没看明白,后面才知道原来求两线段构成个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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值