Line of Sight POJ - 2074 (线段覆盖 )

Line of Sight POJ - 2074 

题目链接:https://vjudge.net/problem/POJ-2074

题意:有房子属性线和障碍物,要求你通过属性线能够看到完整房子的最大属性上的距离

思路:

 

其实将房子右端点和障碍物左端连线,房子左端点和障碍物右端点连线在属性线上的投影部分就是看不到房子的区域,即图中地下红色部分,那么所求就是途中属性线剩下的蓝色大括号,求其最大值,求解过程中还要注意线段的合并,如果没有障碍物那么就输出属性线的长度就行,如果有一个投影线段完全覆盖了属性线,那么就输出"No View”即可

//
// Created by HJYL on 2020/1/22.
//
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int maxn=200;
const double eps=1e-8;
struct Point{
    double x,y;
};
int dcmp1(double x)
{
    if (fabs(x)<eps) return 0;
    else return x<0?-1:1;
}
struct segment{
    Point A,B;
};
struct jiao{//投影在属性线上的每一段
    double l,r;
    bool operator<(const jiao &other)const{
        if(this->l==other.l)
            return this->r<other.r;
        return this->l<other.l;
    }
};
double Multi(Point p1, Point p2, Point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
double seg_cross(Point a, Point b, Point c, Point d)//直线与线段的交点
{
    Point tmp;
    double s1, s2;
    s1 = Multi(b, c, a);
    s2 = Multi(b, d, a);
    tmp.x = ( s2 * c.x - s1 * d.x ) / (s2 - s1);
    tmp.y = ( s2 * c.y - s1 * d.y ) / (s2 - s1);
    return tmp.x;
}
int main()
{
    segment house;
    while(~scanf("%lf%lf%lf",&house.A.x,&house.B.x,&house.A.y)) {
        if (house.A.x == 0 && house.B.x == 0 && house.A.y == 0)
            break;
        house.B.y = house.A.y;
        segment aim;
        scanf("%lf%lf%lf", &aim.A.x, &aim.B.x, &aim.A.y);
        aim.B.y = aim.A.y;
        int num;
        scanf("%d", &num);
            segment tree[maxn];
            for (int i = 0; i < num; i++) {
                scanf("%lf%lf%lf",&tree[i].A.x,&tree[i].B.x,&tree[i].A.y);
                if(tree[i].A.y>house.A.y||tree[i].A.y<aim.A.y)//障碍物纵坐标大于房子或者小于属性线的均可忽略
                {
                    num--;
                    i--;
                    continue;
                }
                tree[i].B.y=tree[i].A.y;
            }
            if(num==0)//如果没有障碍物那么长度就是线段属性线的长度
            {
                printf("%.2lf\n",aim.B.x-aim.A.x);
                continue;
            }
                jiao jj[maxn];
                int ops = 0;
                bool flag=false;
                for (int i = 0; i < num; i++) {
                    jj[ops].l = seg_cross(house.B, tree[i].A, aim.A, aim.B);
                    jj[ops].r = seg_cross(house.A, tree[i].B, aim.A, aim.B);
                    if(jj[ops].l > aim.B.x||jj[ops].r < aim.A.x)//投影下来线段右横坐标小于属性线左边或者投影下来左横坐标大于属性线右边可忽略
                        continue;
                    if(jj[ops].l<aim.A.x&&jj[ops].r>aim.B.x)//障碍物完全挡住了属性线那么就输出"No View"
                    {
                        flag=true;
                        break;
                    }
                    if(jj[ops].l<aim.A.x) jj[ops].l=aim.A.x;//超越属性线的部分端点就按照属性线的端点计算
                    if(jj[ops].r>aim.B.x) jj[ops].r=aim.B.x;
                    ops++;
                }
                if(flag) {
                    printf("No View\n");
                    continue;
                }
                sort(jj, jj + ops);//将投影下来的线段排序
                double ll[maxn],rr[maxn];
                ll[0]=jj[0].l,rr[0]=jj[0].r;
                int pos=0;
                for(int i=1;i<ops;i++)//合并这些线段
                {
                    if(rr[pos]>=jj[i].l)
                        rr[pos]=max(rr[pos],jj[i].r);//线段重合
                    else
                    {
                        pos++;
                        ll[pos]=jj[i].l;
                        rr[pos]=jj[i].r;
                    }
                }
                double maxx = max(ll[0] - aim.A.x, aim.B.x - rr[pos]);//将左右两边端点值先比较出来
                for (int i = 0; i < pos; i++) {
                    maxx = max(maxx, ll[i+1]-rr[i]);
                }
                if (dcmp1(maxx) == 1)
                    printf("%.2lf\n", maxx);
                else
                    printf("No View\n");
    }
    return 0;
}

 

 

 

 

 

posted @ 2020-01-23 16:55  branna  阅读(150)  评论(0编辑  收藏  举报