poj 2826 An Easy Problem?!(计算几何)

不得不说这道题有点爽的样子。。。要考虑很多种细节,可以练练手感,然后的然后我写的好像有点长了。。。

这种题首先思路要理清楚,分为能接到水和不能接到水两种情况,然后能接到水直接用叉乘计算面积

不能接到水的情况有几种要分别讨论

1.有一条线段和x轴平行

2.两条线段不相交

3.两条线段的交点上方不能接到水,也就是说交点与其中一条线段的y坐标最大值那个点重合了

4.两条线段相交,但是位于上方的直线遮盖住了下方的直线

比如这组数据

0 0 2 2

0 0 2 0

只要这些情况都考虑到的话AC还是没问题的,不过我看讨论版里有些人说精度卡的高。。。不理解是哪里卡精度了。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-8;
struct P
{
    double x,y;
    P(){}
    P(double x,double y):x(x),y(y){
    }
    P operator +(P p){
        return P(x+p.x,y+p.y);
    }
    P operator -(P p){
        return P(x-p.x,y-p.y);
    }
    P operator *(double d){
        return P(x*d,y*d);
    }
    double det(P p){
        return x*p.y-y*p.x;
    }
};
struct Line
{
    P a,b;
};
Line q[2];
int n,t;
P in(P p1,P p2,P q1,P q2){
    return p1+(p2-p1)*( (q2-q1).det(q1-p1)/(q2-q1).det(p2-p1) );
}
bool kspc(Line a,Line b)//快速排斥实验
{
    if(min(a.a.x,a.b.x)>max(b.a.x,b.b.x) || max(a.a.x,a.b.x)<min(b.a.x,b.b.x))
    return 0;
    if(min(a.a.y,a.b.y)>max(b.a.y,b.b.y) || max(a.a.y,a.b.y)<min(b.a.y,b.b.y))
    return 0;
    return 1;
}
P r;
bool judge() //判断是否能接水
{
    //判断不相交或者共线返回1
    if(!kspc(q[0],q[1]))
    return 1;
    if(!((q[0].a-q[1].a).det(q[1].b-q[1].a)*(q[0].b-q[1].a).det(q[1].b-q[1].a)<=0 && (q[1].a-q[0].a).det(q[0].b-q[0].a)*(q[1].b-q[0].a).det(q[0].b-q[0].a)<=0))
    return 1;
    if((q[0].a-q[1].a).det(q[1].a-q[1].b)==0.0 && (q[0].b-q[1].a).det(q[1].a-q[1].b)==0.0)
		return 1;
    //判断是否有水平线,返回1
    if(q[0].a.y==q[0].b.y || q[1].a.y==q[1].b.y)
    return 1;
    //判断交点是否在最高点
    if((q[0].a-q[1].a).det(q[1].a-q[1].b)==0.0 || (q[1].a-q[0].a).det(q[0].a-q[0].b)==0.0)
    return 1;
    //最高点在交点同侧且覆盖
    r=in(q[0].a,q[0].b,q[1].a,q[1].b);
    if(q[0].a.x<=r.x && q[1].a.x<=r.x)
    {
		if(q[0].a.y>q[1].a.y && q[0].a.x<=q[1].a.x)
		{
			if((q[0].a-r).det(q[1].a-r)>=0)
				return 1;
		}
		else if(q[0].a.y<=q[1].a.y && q[0].a.x>=q[1].a.x)
		{
			if((q[1].a-r).det(q[0].a-r)>=0)
				return 1;
		}
    }
    if(q[0].a.x>=r.x && q[1].a.x>=r.x)
    {
		if(q[0].a.y>q[1].a.y && q[0].a.x>=q[1].a.x)
		{
			if((q[0].a-r).det(q[1].a-r)<=0)
				return 1;
		}
		else if(q[0].a.y<=q[1].a.y && q[0].a.x<=q[1].a.x)
		{
			if((q[1].a-r).det(q[0].a-r)<=0)
				return 1;
		}
    }
	return 0;
}
double ans;
void solve() //计算面积
{
    P l,d;
    double asd;
    if(q[0].a.y==q[1].a.y)
    {
        asd=(q[0].a-r).det(q[1].a-r);
    }
    else if(q[0].a.y<q[1].a.y)
    {
        if(q[0].a.x<r.x && q[1].a.x<r.x)
        {
            l.x=10000000.0;
            l.y=q[0].a.y;
            d=in(q[0].a,l,q[1].a,q[1].b);
            asd=(d-r).det(q[0].a-r);
        }
        else
        {
            l.x=-10000000.0;
            l.y=q[0].a.y;
            d=in(q[0].a,l,q[1].a,q[1].b);
            asd=(d-r).det(q[0].a-r);
        }
    }
    else
    {
        if(q[0].a.x<r.x && q[1].a.x<r.x)
        {
            l.x=10000000.0;
            l.y=q[1].a.y;
            d=in(q[1].a,l,q[0].a,q[0].b);
            asd=(d-r).det(q[1].a-r);
        }
        else
        {
            l.x=-10000000.0;
            l.y=q[1].a.y;
            d=in(q[1].a,l,q[0].a,q[0].b);
            asd=(d-r).det(q[1].a-r);
        }
    }
    if(asd<0)
    asd=-asd;
    ans=asd/2.0;
    printf("%.2lf\n",ans);
}
int main()
{
   // freopen("intput.txt","r",stdin);
   // freopen("output.txt","w",stdout);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lf%lf%lf%lf",&q[0].a.x,&q[0].a.y,&q[0].b.x,&q[0].b.y);
        scanf("%lf%lf%lf%lf",&q[1].a.x,&q[1].a.y,&q[1].b.x,&q[1].b.y);
        if(q[0].a.y<q[0].b.y)
        swap(q[0].a,q[0].b);
        if(q[1].a.y<q[1].b.y)
        swap(q[1].a,q[1].b);
        if(judge())
        printf("0.00\n");
        else
        solve();
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值