UVa 221 - Urban Elevations

题意

城市俯视图 给出坐标,长宽高, 求从南向北(朝着y周正方向)看, 正视图能看到的楼号

思路

因为坐标可能会有double类型的, 所以没法枚举每一个横坐标
这里引用一下紫书的思路
记得控制一下格式

把所有x坐标排序去重,则任意两个相邻x坐标形成的区间具有相同属性,一个区间要么完全可见,要么完全不可见。这样,只需在这个区间里任选一个点(例如中点),就能判断出一个建筑物是否在整个区间内可见。如何判断一个建筑物是否在某个x坐标处可见呢?首先,建筑物的坐标中必须包含这个x坐标,其次,建筑物南边不能有另外一个建筑物也包含这个x坐标,并且不比它矮。

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>

using namespace std;
const int maxn = 300;
set<int> setid;
set<double> setdx;
double dx[maxn];

struct building{
    int id;
    double x,y,w,d,h,xx;
}p[maxn/2];

bool cmp( struct building a, struct building b )
{
    if( a.x == b.x )
        return a.y < b.y;
    return a.x < b.x;
}
int T;
bool judge( double point, struct building a ){
    if( a.y == 0 )  return true;
    if( a.xx < point || a.x > point )   return false;
    for( int i = 0; i < T; i++ ){
        //cout << "point : " << point << " xx : " << p[i].xx << endl;
        if( point >= p[i].x && point <= p[i].xx ){
            if( p[i].y < a.y && p[i].h >= a.h )
                return false;
        }
    }
    return true;
}

int main()
{
    int i, j, len, num, casenum = 0;
    while( scanf("%d",&T) == 1 && T ){
        for( i = 0; i < T; i++ ){
            p[i].id = i+1;
            scanf("%lf%lf%lf%lf%lf",&p[i].x,&p[i].y,&p[i].w,&p[i].d,&p[i].h);
            p[i].xx = p[i].x + p[i].w;
            if(!setdx.count(p[i].x))  setdx.insert(p[i].x);
            if(!setdx.count(p[i].xx))  setdx.insert(p[i].xx);
        }
        set<double>::iterator it;
        for( it = setdx.begin(), i = 0; it != setdx.end(); it++, i++ )
            dx[i] = *it;
        len = i;
        sort(p, p+T, cmp);
        if( casenum != 0 )  putchar('\n');
        printf("For map #%d, the visible buildings are numbered as follows:\n",++casenum);
        num = 0;
        for( i = 0; i < T; i++ ){
            if( setid.count(p[i].id) )  continue;
            for( j = 0; j < len; j++ ){
                if( p[i].xx < dx[j] )  break;
                if( dx[j] >= p[i].x || dx[j+1] <= p[i].xx ){
                    if( judge( (dx[j]+dx[j+1])/2.0 ,p[i] ) ){
                        if( ++num != 1 )    printf(" ");
                        printf("%d",p[i].id);
                        setid.insert(p[i].id);
                        break;
                    }
                }
            }
        }
        putchar('\n');
        if( !setid.empty() )    setid.clear();
        if( !setdx.empty() )    setdx.clear();
        memset(dx,0,sizeof(dx));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值