UVA 221 Urban Elevations (离散化)

An elevation of a collection of buildings is an orthogonal projection of the buildings onto a vertical plane. An external elevation of a city would show the skyline and the faces of the ``visible" buildings of the city as viewed from outside the city from a certain direction. A southern elevation shows no sides; it shows the perfectly rectangular faces of buildings or parts of faces of buildings not obstructed on the south by taller buildings. For this problem, you must write a program that determines which buildings of a city are visible in a southern elevation.

For simplicity, assume all the buildings for the elevation are perfect rectangular solids, each with two sides that run directly east-west and two running directly north-south. Your program will find the buildings that appear in a southern elevation based on knowing the positions and heights of each city building. That data can be illustrated by a map of the city as in the diagram on the left below. The southern elevation for that city is illustrated in the diagram on the right.

(The shadow buildings are visible in a southern elevation)

Input

Input for your program consists of the numeric description of maps of several cities. The first line of each map contains the number of buildings in the city (a non-negative integer less than 101). Each subsequent line of a map contains data for a single building - 5 real numbers separated by spaces in the following order:

 
		 x-coordinate of the southwest corner

y-coordinate of the southwest corner

width of the building (length of the south side)

depth of the building (length of the west side)

height of the building

Each map is oriented on a rectangular coordinate system so that the positive x-axis points east and the positive y-axis points north. Assume that all input for each map corresponds to a legitimate map (the number of buildings is the same as the number of subsequent lines of input for the map; no two buildings in a single map overlap). Input is terminated by the number 0 representing a map with no buildings.

Output

Buildings are numbered according to where their data lines appear in the map's input data - building #1 corresponding to the first line of building data, building #2 data to the next line, and building #n to thenth line of building data for that map. (Buildings on subsequent maps also begin their numbering with 1.)

For each map, output begins with line identifying the map (map #1map #2, etc.) On the next line the numbers of the visible buildings as they appear in the southern elevation, ordered south-to-north, west-to-east. This means that if building n and building m are visible buildings and if the southwest corner of building nis west of the southwest corner of building m, then number n is printed before number m. If building n and building m have the same x-coordinate for their southwest corners and if building n is south of building m, then the number n is printed before the number m.

For this program, a building is considered visible whenever the part of its southern face that appears in the elevation has strictly positive area. One blank line must separate output from consecutive input records.

Sample Input

14
160 0 30 60 30
125 0 32 28 60
95 0 27 28 40
70 35 19 55 90
0 0 60 35 80
0 40 29 20 60
35 40 25 45 80
0 67 25 20 50
0 92 90 20 80
95 38 55 12 50
95 60 60 13 30
95 80 45 25 50
165 65 15 15 25
165 85 10 15 35
0

Sample Output

For map #1, the visible buildings are numbered as follows:
5 9 4 3 10 2 1 14
 
思路:
    根据题意,按x坐标排序,然后判断每个建筑物是否可见。注意到建筑物可见性等价于南墙的可见性。判断可见性看上去比较麻烦,因为x坐标是无穷的,无法枚取所有的x来判断某个建筑物在该处可见。因此可以离散化x,把无穷变有限。
    具体做法:把所有x坐标排序去重,则任意两个相邻的x坐标形成的区间具有相同的属性,一个区间要么完全可见,要么完全不可见。因此,只需在这个区间内任取取一点(如中点),就能判断一个建筑物在整个区间内是否可见。如何判断呢?首先,建筑物的坐标中必须包含这个x坐标,其次,建筑物南边(它的前面)不能有另一个建筑物也包含这个x坐标,并且后者建筑物不能比前者高。
 
代码:

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <string>

using namespace std;

const int maxn =105;
double x[maxn*2];
int n;

struct bul
{
    int ID;
    double x,y,w,d,h;
    bool operator <(const bul &a) const
    {
        return x<a.x||(x==a.x&&y<a.y);//根据输出顺序,重载 < 操作符
    }
}b[maxn];

bool xcover(int i,double mx)//建筑物i是否包含 x=mx
{
    return (b[i].x<=mx)&&(b[i].x+b[i].w)>=mx;
}

bool visible(int i,double mx)
{
    if(!xcover(i,mx))
        return false;
    for(int k=0;k<n;k++)//建筑物i与每个建筑物k比较
    {
        if(b[k].y<b[i].y&&b[k].h>=b[i].h&&xcover(k,mx))//三个条件
            return false;
    }
    return true;
}

int main()
{
    int kase=0;
    while(cin>>n&&n)
    {
        for(int i=0;i<n;i++)
        {
            cin>>b[i].x>>b[i].y>>b[i].w>>b[i].d>>b[i].h;
            b[i].ID=i+1;
            x[i*2]=b[i].x;//建筑物i的x坐标区间
            x[i*2+1]=b[i].x+b[i].w;
        }

        sort(b,b+n);
        sort(x,x+n*2);//排序
        int m=unique(x,x+n*2)-x;//去重,得到m个坐标

        if(kase++)
            cout<<endl;
        cout<<"For map #"<<kase<<", the visible buildings are numbered as follows:"<<endl<<b[0].ID;

        for(int i=1;i<n;i++)//判断每个建筑物
        {
            bool vis=false;
            for(int j=0;j<m-1;j++)
            {
                if(visible(i,(x[j]+x[j+1])/2))//判断建筑物i在 x=mx 是否可见
                {
                    vis=true;
                    break;
                }
            }
            if(vis)
                cout<<" "<<b[i].ID;
        }
        cout<<endl;
    }
    return 0;
}



                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值