POJ-2074

题目源于网络:
An architect is very proud of his new home and wants to be sure it can be seen by people passing by his property line along the street. The property contains various trees, shrubs, hedges, and other obstructions that may block the view. For the purpose of this problem, model the house, property line, and obstructions as straight lines parallel to the x axis:
To satisfy the architect’s need to know how visible the house is, you must write a program that accepts as input the locations of the house, property line, and surrounding obstructions and calculates the longest continuous portion of the property line from which the entire house can be seen, with no part blocked by any obstruction.
Input
Because each object is a line, it is represented in the input file with a left and right x coordinate followed by a single y coordinate:
< x1 > < x2 > < y >
Where x1, x2, and y are non-negative real numbers. x1 < x2
An input file can describe the architecture and landscape of multiple houses. For each house, the first line will have the coordinates of the house. The second line will contain the coordinates of the property line. The third line will have a single integer that represents the number of obstructions, and the following lines will have the coordinates of the obstructions, one per line.
Following the final house, a line “0 0 0” will end the file.
For each house, the house will be above the property line (house y > property line y). No obstruction will overlap with the house or property line, e.g. if obstacle y = house y, you are guaranteed the entire range obstacle[x1, x2] does not intersect with house[x1, x2].
Output
For each house, your program should print a line containing the length of the longest continuous segment of the property line from which the entire house can be to a precision of 2 decimal places. If there is no section of the property line where the entire house can be seen, print “No View”.
Sample Input
2 6 6
0 15 0
3
1 2 1
3 4 1
12 13 1
1 5 5
0 10 0
1
0 15 1
0 0 0
Sample Output
8.80
No View
文章大意是从一条道路上看某一栋房子,道路与房子之间有障碍物,三者都看成是线段,问题是问在这条道路上能完整看见这栋房子所化直线的最长连续距离是多少。
解析:将道路看成是一个区间,通过对某一个障碍物求被遮挡的区间,消除合并重复区间,最后这条道路上最大的没有被占用的连续区间长度就是所求。

//这题磨了我好久,幸好在网上看到了一个大佬贴出来的一些测试点,我放在文章末尾,然后跟着测试用例错误的地方一个一个改,以下我把特别需要注意的地方标注出来
`#include<iostream>
#include<math.h>
#include <algorithm>
#include<stdio.h>
#include<string.h>
#include<stack> 
#include<queue>
using namespace std;
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a))) 
#define w while
typedef long long ll;

double lx, rx, y; 
double dlx, drx, dy;
int n;
struct acm{
    double xt1;
    double xt2;
    double yt;
}a[2110];

struct node{
    double lxx;
    double rxx;
}p[2110];

bool cmp(acm c,acm d)
{
    return c.xt1 < d.xt2;
}

bool cmp1(node c,node d)
{
    return c.lxx < d.lxx;
}

int main()
{
    w(scanf("%lf%lf%lf",&lx, &rx, &y) && lx && rx && y)
    {   
    scanf("%lf%lf%lf",&dlx, &drx, &dy);
    sc(n);
    rep(i, 0, n)
    scanf("%lf%lf%lf",&a[i].xt1, &a[i].xt2, &a[i].yt);
    sort(a, a+n, cmp);//按左端x排序
    ms(p, 0);
    double k, t, b;
    int j = 0;

    rep(i, 0, n)
    {
        if(a[i].yt >= y || a[i].yt <= dy)//超过建筑物的和低于物业线的不考虑
        continue;
        if(a[i].xt2 <= dlx || a[i].xt1 >= drx)//不在物业线范围内的也不考虑
        continue;
        t = y - a[i].yt;
        //房屋右端点和阻碍物左端点连线交点就是看不见的区间的左端点
        if(a[i].xt1 == rx)
        {
            p[j].lxx = a[i].xt1;
        }
        else
        {
            k = t / (rx - a[i].xt1);
            b = y - k * rx;
            p[j].lxx = (dy - b) / k;
        }
        //房屋左端点和阻碍物右端点连线交点就是看不见的区间的右端点
        if(a[i].xt2 == lx)
        {
            p[j++].rxx = a[i].xt2;
        }
        else
        {
            k = t / (lx - a[i].xt2);
            b= y - k * lx;
            p[j++].rxx = (dy - b) / k;
        }


    }
    if(j == 0)//如果没有在道路和房子中间的,当然任何位置都能看见
    {
        pf("%.2lf\n",drx - dlx);
        continue;
    }
    sort(p, p+j, cmp1);//按这些区间的左端点排序
    //把这些区间重复的部分合并
    rep(i, 1, j)
    {
        if(p[i-1].lxx >= p[i].lxx && p[i-1].rxx <= p[i].rxx)
        {
            p[i-1].lxx = -1000000000;
            p[i-1].rxx = -1000000000;
        }
        else if(p[i-1].lxx >= p[i].lxx && p[i-1].lxx <= p[i].rxx && p[i-1].rxx > p[i].rxx)
        {
            p[i].rxx = p[i-1].rxx;
            p[i-1].lxx = -1000000000;
            p[i-1].rxx = -1000000000;
        }
        else if(p[i-1].lxx < p[i].lxx && p[i-1].rxx <= p[i].rxx && p[i-1].rxx >= p[i].lxx)
        {
            p[i].lxx = p[i-1].lxx;
            p[i-1].lxx = -1000000000;
            p[i-1].rxx = -1000000000;
        }
      //这里特别要注意,像测试用例4, 1 5 2,可能这个区间左端点排序后在较前位置,但是他的右端点很大,所以可能出现以下这种情况。
        else if(p[i-1].lxx <= p[i].lxx && p[i-1].rxx >= p[i].rxx)
        {
            p[i].lxx = p[i-1].lxx;
            p[i].rxx = p[i-1].rxx;
            p[i-1].lxx = -1000000000;
            p[i-1].rxx = -1000000000;
        }
      //其实把这四种情况合并写,更不容易犯错,只要满足以上四种某种条件,直接取两个人的左端点的最小值和右端点的最大值,就不用写这么多了。
    }
    //这些赋值就是为了在下面f为0时可以取到负的结果,怕有超出情况,多赋值了几个,一般来说一个就够了
    p[j].lxx = -1000000000;
    p[j].rxx = 1000000000;
    p[j+1].lxx = -1000000000;
    p[j+1].rxx = 1000000000;
    p[j+2].lxx = -1000000000;
    p[j+2].rxx = 1000000000;
    p[j+3].lxx = -1000000000;
    p[j+3].rxx = 1000000000;
    double ans;
    sort(p, p+j, cmp1);//再一次排序,把这些有用的区间放到相邻位置,方便操作
    int r = 0, f;//f用来标记,可能存在最后一个可用区间的右端点没有超过物业线右端点,如最后一个测试用例
    //先检索到非空区间
    w(p[r].lxx == -1000000000 && p[r].rxx == -1000000000 && r < j)
    r++;
    f=r;//如果区间全空,f为0
    if(p[r].lxx <= drx)
    ans = p[r].lxx - dlx;
    else ans = drx - dlx;
    rep(i, r+1, j)
    if(p[i].lxx <= drx)
    {
        ans = max(ans, p[i].lxx - p[i-1].rxx);
        f = i;
    }
    else break; 
    ans = max(ans, drx - p[f].rxx);
    if(ans <= 0)
    pf("No View\n");
    else
    pf("%.2lf\n",ans);
    }
    return 0;
}
/*2 6 6
0 15 0
3
1 2 1
3 4 1
12 13 1
1 5 5
0 10 0
1
0 15 1
2 6 6
0 15 0
3
1 2 1
3 4 1
12 13 1
2 6 6//我这里错了
0 15 0
4
1 2 1
3 4 1
12 13 1
1 5 2
2 6 6
0 15 0
2
0 5 3
6 15 3
2 6 6
0 15 0
2
6 10 1
0 2 1
2 6 6
0 15 0
1
2 6 7
2 6 6
0 15 0
1
2 6 7
2 6 6
0 15 0
1
4 4.5 5.5
2 6 6
0 15 0
16
0 1 3
1.5 2 3
2.5 3 3
3.5 4 3
4.5 5 3
5.5 6 3
6.5 7 3
7.5 8 3
8.5 9 3
9.5 10 3
10.5 11 3
11.5 12 3
12.5 13 3
13.5 14 3
14.5 15 3
15.5 16 3
2 6 6
0 15 0
16
0 1 .1
1.5 2 .1
2.5 3 .1
3.5 4 .1
4.5 5 .1
5.5 6 .1
6.5 7 .1
7.5 8 .1
8.5 9 .1
9.5 10 .1
10.5 11 .1
11.5 12 .1
12.5 13 .1
13.5 14 .1
14.5 15 .1
15.5 16 .1
2 6 6
0 15 0
14
0 1 3
1.5 2 3
2.5 3 3
3.5 4 3
4.5 5 3
5.5 6 3
8.5 9 3
9.5 10 3
10.5 11 3
11.5 12 3
12.5 13 3
13.5 14 3
14.5 15 3
15.5 16 3
2 6 6//这个也错了
0 4000000000 0
2
1 2 1 
15 16 3
2 6 6//还有这个
0 15 1
5
1 1.5 6
17 18 1 
3 5 3
0 20 10
0 20 0.5
*/
//答案:
//8.80
//No View
//8.80
//6.70
//No View
//4.00
//15.00
//15.00
//No View
//No View
//0.44
//1.00
//3999999970.00
//8.00
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值