An Easy Problem?! POJ - 2826

本文探讨了如何计算两条线段形成的区域能够盛放的最大水量。文章详细介绍了判断线段是否相交和平行的方法,并给出了针对不同情况的计算公式。此外,还提供了一份完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

点击打开链接

一开始真以为是水题 然后WA了一天

 

 

两线段所在直线的关系有平行与相交

首先平行绝对不可以 去掉平行时顺带去掉了重叠或部分重叠这一情况

若相交且可以盛水 则四个端点中必有两个在交点上方

分类讨论

 

1. 两点在交点异侧

    这种情况下必然可以盛水 直接计算(详见代码)

2. 两点在交点同侧

 

    这时可能会存在上方的线段l1(p0p1)将下方的线段l2(p0p2)完全盖住而无法盛水的情况 必须注意

    这种情况通过比较 1与l2的斜率 及 p1与p2的端点 即可判别

 

 

 

还有 实在过不了记得把答案加个eps 坑。。

 

 

 

 

 

 

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
#define eps 1e-8

struct node
{
    double x;
    double y;
};

double cal(node a,node b,node c)//AB X AC
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}

double getx(double y,node p1,node p2)
{
    return (p2.x-p1.x)*(y-p2.y)/(p2.y-p1.y)+p2.x;
}

double getk(node p1,node p2)
{
    return (p2.y-p1.y)/(p2.x-p1.x);
}

bool judge(node a,node b,node c,node d)
{
    if(cal(a,b,c)*cal(a,b,d)<eps&&cal(c,d,a)*cal(c,d,b)<eps&&getk(a,b)!=getk(c,d))
    {
        return true;
    }
    else return false;
}

node getpoint(node a,node b,node c,node d)
{
    node res;
    double a1,b1,c1,a2,b2,c2;
    a1=a.y-b.y,b1=b.x-a.x,c1=a.x*b.y-b.x*a.y;
    a2=c.y-d.y,b2=d.x-c.x,c2=c.x*d.y-d.x*c.y;
    res.x=(b1*c2-b2*c1)/(a1*b2-a2*b1);
    res.y=-(a1*c2-a2*c1)/(a1*b2-a2*b1);
    return res;
}

void solve(node p0,node p1,node p2)
{
    node tp;
    double ans,tx;
    ans=0;
    if(fabs(p0.x-p1.x)<eps||fabs(p0.x-p2.x)<eps||(p0.x-p1.x>eps&&p0.x-p2.x<eps)||(p0.x-p1.x<eps&&p0.x-p2.x>eps))//102 201
    {
        if(p2.y-p1.y>eps)
        {
            tx=getx(p1.y,p0,p2);
            ans=fabs(p1.x-tx)*(p1.y-p0.y)/2;
        }
        else
        {
            tx=getx(p2.y,p0,p1);
            ans=fabs(p2.x-tx)*(p2.y-p0.y)/2;
        }
    }
    else if(p0.x-p1.x<eps&&p0.x-p2.x<eps)//012
    {
        if(p2.y-p1.y>eps)
        {
            if(getk(p0,p1)-getk(p0,p2)>eps||(getk(p0,p1)-getk(p0,p2)<eps&&p1.x-p2.x>0))
            {
                tx=getx(p1.y,p0,p2);
                ans=fabs(p1.x-tx)*(p1.y-p0.y)/2;
            }
        }
        else
        {
            if(getk(p0,p2)-getk(p0,p1)>eps||(getk(p0,p2)-getk(p0,p1)<eps&&p2.x-p1.x>0))
            {
                tx=getx(p2.y,p0,p1);
                ans=fabs(p2.x-tx)*(p2.y-p0.y)/2;
            }
        }
    }
    else if(p0.x-p1.x>eps&&p0.x-p2.x>eps)//120
    {
        if(p2.y-p1.y>eps)
        {
            if(getk(p0,p1)-getk(p0,p2)<eps||(getk(p0,p1)-getk(p0,p2)>eps&&p1.x-p2.x<0))
            {
                tx=getx(p1.y,p0,p2);
                ans=fabs(p1.x-tx)*(p1.y-p0.y)/2;
            }
        }
        else
        {
            if(getk(p0,p2)-getk(p0,p1)<eps||(getk(p0,p2)-getk(p0,p1)>eps&&p2.x-p1.x<0))
            {
                tx=getx(p2.y,p0,p1);
                ans=fabs(p2.x-tx)*(p2.y-p0.y)/2;
            }
        }
    }
    printf("%.2f\n",ans+eps);
    return;
}

int main()
{
    node pre[2];
    node p0,p1,p2,p3,p4;
    int t,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y,&p3.x,&p3.y,&p4.x,&p4.y);
        if(!judge(p1,p2,p3,p4))
        {
            printf("0.00\n");
            continue;
        }
        p0=getpoint(p1,p2,p3,p4);
        i=0;
        if(p1.y-p0.y>eps) pre[i++]=p1;
        if(p2.y-p0.y>eps) pre[i++]=p2;
        if(p3.y-p0.y>eps) pre[i++]=p3;
        if(p4.y-p0.y>eps) pre[i++]=p4;
        if(i<2)
        {
            printf("0.00\n");
            continue;
        }
        solve(p0,pre[0],pre[1]);
    }
    return 0;
}

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值