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;
}

原文地址:https://www.cnblogs.com/Vampire6/p/12230844.html

时间: 2024-10-14 16:44:01

Line of Sight POJ - 2074 (线段覆盖 )的相关文章

POJ 2074 | 线段相交

#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define eps 1e-8 using namespace std; bool dcmp(double x,double y) { if (fabs(x-y)>eps) return 1; return 0; } struct point { double x,y; point () {}; point (

Mayor&#39;s posters POJ - 2528 线段树区间覆盖

//线段树区间覆盖 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=100010; int flag; struct node{ int l,r; //vis 是这块区域是否完全被覆盖 bool vis; }tr[N<<2]; struct point { int id; int x

POJ 3347 Kadj Squares (线段覆盖)

题目大意:给你几个正方形的边长,正方一个顶点在x轴上然后边与x轴的夹角为45度,每个正方形都是紧贴的,问从上面看能看的正方形的编号 题目思路:线段覆盖,边长乘上2防止产生小数,求出每个正方形与x轴平行的对角线的起始x坐标,剩下的就是线段了. #include<cstdio> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<cs

poj 2777 线段树的区间更新

Count Color Time Limit: 1000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description Chosen Problem Solving and Program design as an optional course, you are required to solve al

POJ 2653 线段交

思路: 运用队列存储没有被覆盖的木棍,没加入一个棍子,就要判断一下是否队列中的棍子被覆盖,如果被覆盖,就从队列中删除: 线段交判断方法:跨立实验 Pick-up sticks Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 9698 Accepted: 3591 Description Stan has n sticks of various length. He throws them one at a time on th

Mayor&#39;s posters POJ - 2528 (线段树 + 离散化)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 86160   Accepted: 24734 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

poj 2653 线段与线段相交

Pick-up sticks Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 11884   Accepted: 4499 Description Stan has n sticks of various length. He throws them one at a time on the floor in a random way. After finishing throwing, Stan tries to fin

poj 1269 线段与线段相交

Intersecting Lines Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13605   Accepted: 6049 Description We all know that a pair of distinct points on a plane defines a line and that a pair of lines on a plane will intersect in one of three

POJ 2528 (线段树+离散化) Mayor&#39;s posters

因为将每个单位都作为一个最小单元的话会爆内存的 所以,将海报的每个端点进行排序,将这些端点最为最小的区间. 毕竟是刚刚接触线段树,理解起来还有些吃力,还是那句话,题做多了慢慢就好了. 萌萌的AC代码君贴上. 1 //#define LOCAL 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 int n; 8 struct CPost 9