poj 2704 Line of Sight(数学型计算几何)

该博客主要介绍了POJ 2704题目的解题思路,涉及计算几何问题。题目要求根据房子和路的坐标,以及多个障碍物的位置,计算避开障碍物后从路上能看到房子的最远距离。解题过程中,需要对障碍物和房子进行连线投影,并对投影结果排序。博主分享了在实现过程中遇到的困难,如障碍物和路的纵坐标不会相同,以及投影可能超出路的范围等问题,这些问题导致了多次错误。最终,博主通过简化数据结构和优化算法找到了解决方案,尽管代码因此显得较为冗长。

【题目大意】给出房子的坐标表示为(x1,x2,y)代表房子所在二维坐标系上的位置,给出路的坐标表示(rx1,rx2,ry)同样表示路在二维坐标系上的位置。然后给出n个障碍物,每个障碍物的坐标表示是(a[i].x1,a[i].x2,a[i].y),问在路上避过障碍物可以连续的看到房子的最远距离是多少。


【解题思路】先对房子和障碍物进行连线构建投影,再按照投影得到在路上的坐标进行排序,最后取即刻。

                     哎,说起来很简单,写起来就....T_T....各种哭爹叫娘。

                     首先,障碍物跟房子和路都不会是同一个纵坐标;另外,投影可能会投影在路外面....足足wa了我8次,8次啊.....

                    刚开始开了线段这个结构体以为要用到,后来发现其实坐标点都没什么用,有用的还是横坐标而已~~懒得改回来了~程序就显得冗长一点。


【代码】:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>

using namespace std;

#define eps 1e-9

struct Point{
    double x,y;
    Point(){}
    Point(double a,double b){
        x=a,y=b;
    }
};

struct Line{
    Point a,b;
    Line() {}
    Line(Point x,Point y){
        a=x,b=y;
    }
};

struct Region{
    double l,r;
};

double x1,y,x2,rx1,rx2,ry,ans;
int n;
Point obl[10000],obr[10000];
Point rl,rr,hl,hr;
Region Reg[10000];

double getPoint(const Point &a,const Point &b){
    if(a.x==b.x) return a.x;
    return a.x+(rl.y-a.y)/((a.y-b.y)/(a.x-b.x));
}

void get_linemap(){
    for (int i=0; i<n; i++){
        double ll=getPoint(obl[i],hr);  //连接两点做延长线求与Road的交点横坐标
        double rrr=getPoint(obr[i],hl);
        if(ll>rx2+eps||rrr+eps<rx1) {n--; i--; continue;} //如果左投影在路的右边,或者右投影在路的左边则跳过
        if (ll>rl.x) Reg[i].l=ll; else Reg[i].l=rl.x;
        if (rrr<rr.x) Reg[i].r=rrr; else Reg[i].r=rr.x;
    }
    return ;
}

bool cmp(const Region &a,const Region &b){
    if (fabs(a.l-b.l)<eps) return a.r+eps<b.r;
    else return a.l+eps<b.l;
}

void solve(){
    ans=0;
    sort(Reg,Reg+n,cmp);
    double tmp=rx1;     //表示现在的左端点
    for(int i=0; i<n; i++)
    {
        if(Reg[i].l>tmp+eps)
        {
            if (ans<Reg[i].l-tmp) ans=Reg[i].l-tmp;
            tmp=Reg[i].r;  //更新左端点
        }
        else if(Reg[i].r>tmp+eps)
            tmp=Reg[i].r;
    }
    if(tmp+eps<rx2)
        if (ans<rx2-tmp) ans=rx2-tmp;   //对右端点的一截进行特殊处理
    return ;
}

int main(){
    while (~scanf("%lf%lf%lf",&x1,&x2,&y)){
        hl=Point(x1,y);
        hr=Point(x2,y);
        if (x1==0 && x2==0 && y==0) break;
        scanf("%lf%lf%lf",&rx1,&rx2,&ry);
        rl=Point(rx1,ry);
        rr=Point(rx2,ry);
        scanf("%d",&n);
        double a,b,c;
        for (int i=0; i<n; i++){
            scanf("%lf%lf%lf",&a,&b,&c);
            if (c+eps<ry||fabs(c-ry)<eps||c>=y+eps||fabs(c-y)<eps) {i--; n--;continue;} //判断障碍物是否在路和房子之间,障碍物不与路和房子在同意水平线上
            obl[i]=Point(a,c);
            obr[i]=Point(b,c);
       //   ob[i].Line(obl[i],obr[i]);
        }
        get_linemap(); //连接障碍物的左端点和房子的右端点,连接障碍物的右端点和房子的左端点,分别求出起在路上的最小范围投影。
        if (n==0) ans=rx2-rx1;
        else solve();
        if (ans>eps) printf("%.2f\n",ans);
        else printf("No View\n");
    }
    return 0;
}


                     

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值