poj 2074

来源:互联网 发布:软件测试难学吗 编辑:程序博客网 时间:2024/05/29 16:17

题目概述

有一座房子建在道路旁边且和道路隔着一段距离,房主希望路人能完整看到房子朝向道路的那一面,但房子和道路之间隔着有一些障碍物,如果将道路,房子,障碍物都视为平行于x轴的线段,给定这些线段端点的坐标,求道路上最长的一段路使得路人可以完整的看到房子的正面
障碍物不会和房子相交,但可能和房子共线

时限

1000ms/3000ms

输入

第一行三个非负浮点数hx1,hx2,hy,描述房子线段的左端点横坐标,右端点横坐标,纵坐标,第二行三个非负浮点数lx1,lx2,ly,类似的描述道路,第三行正整数N,代表障碍物数,其后N行,每行三个浮点数x1,x2,y,类似的描述障碍物,输入到hx1=hx2=hy=0结束

限制

所有左端点横坐标<右端点横坐标;hy>ly

输出

每组数据在一行中输出,若存在符合条件的路,输出一个保留两位的浮点数,代表其最长长度,若从路的任何位置都无法完整看到房子正面,输出字符串
No View

样例输入

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 12 0
3
1 2 1
3 4 1
12 13 1

2 6 6
6 15 0
3
1 2 1
3 4 1
12 13 1

2 6 6
0 15 0
3
1 2 -1
3 4 -1
12 13 -1

2 6 6
0 15 0
3
1 2 10
3 4 10
12 13 10

2 6 6
0 15 0
0

2 6 6
0 15 0
1
0 15 1

0 0 0

样例输出

8.80
No View
7.60
7.20
15.00
15.00
15.00
15.00
No View

讨论

计算几何,求直线与直线交点,外加一点贪心(可能吧),先抛开各种坑不谈,计算视线,就是过房子左端点和障碍物右端点做直线,然后过房子右端点和障碍物左端点做直线,两条直线和路所在直线交与两点,这两点之间都算盲区,为啥?额只能说找张纸或者用几何画板画画就能看出来,求得一堆盲区后按左端点升序排序,然后根据右端点位置找出非盲区,考察相邻的两段盲区,如果下一个的左端点在上一个的右端点左侧,这两段盲区会覆盖成一个大盲区,记录一下右端点位置,否则,上一个的右端点到下一个的左端点之间就是一段非盲区,更新一下最大值,然后同样视为一个大盲区,记录大盲区右端点位置,到最后就会得到最大的一段非盲区长度
再来看一些坑点,题目说障碍物会和房子共线的时候已经有提醒了,显然只有房子和道路之间的障碍物会遮挡视线,于是将不在这个范围的障碍物遮挡的范围设为一个微小(0)的且绝对不在路上(-INF)的位置,第5,6组数据可以测试这一点,另外需要注意盲区的端点可能会落在路的外面,在路外面的一段是不能算的,通过比较端点和路端点位置关系可以解决,第3,4组数据可以测试这一点,再有就是对于没有障碍物的情况,由于这样就不会计算盲区位置,会导致输出无视野,因而可以人为添加两段盲区,把路的端点两侧覆盖,强制计算出一段非盲区(整条路),第7组数据可以测试这一点
另外题目也没说数据规模,额猜的100,竟然够了

题解状态

192K,0MS,C++,1735B

题解代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;#define INF 0x3f3f3f3f  #define MAXN 103#define memset0(a) memset(a,0,sizeof(a))#define EPS 1e-6struct Blocked//盲区结构{    double x1, x2;//左右端点横坐标    bool operator<(Blocked &b)const    {        return x1 < b.x1;    }}block[MAXN];int N;//障碍物数double hx1, hx2, hy, lx1, lx2, ly;//house 房子的左右端点横坐标和纵坐标 line 道路的int signal(double a)//符号函数 这东西越来越好用{    if (abs(a) < EPS)        return 0;    else if (a > 0)        return 1;    else        return -1;}double point_of_intersection_x(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)//求直线交点横坐标 点3点4是留给路的 由于路一定是水平 因而简单不少{    if (!signal(x1 - x2))        return x1;    double k1 = (y2 - y1) / (x2 - x1);    return (y1 - y3 - k1*x1) / (-k1);//解方程去 不要空想}void fun(){    block[N].x1 = -INF, block[N].x2 = lx1;    block[N + 1].x1 = lx2, block[N + 1].x2 = INF;//人为添加的两段盲区 防止没有障碍物的情况    for (int p = 0; p < N; p++) {        double x1, x2, y;        scanf("%lf%lf%lf", &x1, &x2, &y);//input//一边读数 顺手算出交点        if (signal(hy - y) != 1 || signal(y - ly) != 1) {//无关紧要的障碍物位置            block[p].x1 = block[p].x2 = -INF;//虽说写0也能过 但是谨慎起见 还是扔远一点            continue;        }        block[p].x2 = point_of_intersection_x(hx1, hy, x2, y, lx1, ly, lx2, ly);        block[p].x1 = point_of_intersection_x(hx2, hy, x1, y, lx1, ly, lx2, ly);//求得两个交点    }    sort(block, block + N + 2);//排序 包含了两个额外盲区    double most = -INF, right = block[0].x2;//最长的非盲区长度 盲区右端点位置 以第一段初始化 方便后面处理    for (int p = 1; p < N + 2; p++) {        if (block[p].x1 > block[p - 1].x2)//如果下一个的左端点在上一个的右端点右侧 即存在非盲区            most = max(most, (block[p].x1>lx2 ? lx2 : block[p].x1) - (right > lx1 ? right : lx1));//算出非盲区的长度 两个?:算符使得非盲区不得超出路的范围        right = max(right, block[p].x2);//最后更新一下大盲区右端点位置    }    if (signal(most) == 1)        printf("%.2lf\n", most);//output    else        printf("No View\n");//output}int main(void){    //freopen("vs_cin.txt", "r", stdin);    //freopen("vs_cout.txt", "w", stdout);    while (~scanf("%lf%lf%lf", &hx1, &hx2, &hy) && (signal(hx1) || signal(hx2) || signal(hy))) {//input//没办法 题目说非得3个0才能停下来        scanf("%lf%lf%lf", &lx1, &lx2, &ly);//input        scanf("%d", &N);//input        fun();    }}

EOF

0 0