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.
City map. Boldface numbers (in the upper left of each building) identify the buildings. Plain numbers (lower right) are the buildings heights.
Southern Elevation (Only the shaded 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 the nth 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 #1, map #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 n is 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
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 const int maxn=105; 6 using namespace std; 7 struct building 8 { 9 int id; 10 double x,y,w,d,h; 11 bool operator<(const building &rhs)const 12 { 13 return x<rhs.x||(x==rhs.x&&y<rhs.y); 14 } 15 }b[maxn]; 16 int n; 17 double x[maxn*2]; 18 bool cover(int i,int mx)//判断在这个离散的点mx间有没有建筑b[i] 19 { 20 return b[i].x<=mx&&b[i].x+b[i].w>=mx; 21 } 22 bool visible(int i,int mx)//判断mx处的建筑b[i]是否可见 23 { 24 if(!cover(i,mx)) 25 return false; 26 for(int k=0;k<n;k++) 27 { 28 if(b[k].y<b[i].y&&b[k].h>=b[i].h&&cover(k,mx)) 29 return false; 30 }return true; 31 } 32 int main() 33 { 34 int kase=0; 35 while(scanf("%d",&n)==1,n) 36 { 37 if(kase++)printf(" ");//不写这行PE 38 printf("For map #%d, the visible buildings are numbered as follows: ",kase); 39 for(int i=0;i<n;i++) 40 { 41 scanf("%lf%lf%lf%lf%lf",&b[i].x,&b[i].y,&b[i].w,&b[i].d,&b[i].h); 42 x[i*2]=b[i].x,x[i*2+1]=b[i].x+b[i].w;//x[]记录所有离散的点 43 b[i].id=i+1; 44 } 45 sort(b,b+n);//对b[]进行排序 46 sort(x,x+2*n); 47 int m=unique(x,x+2*n)-x;//去重,得到去重后的不同点的个数 48 for(int i=0;i<n;i++)//对每个建筑进行判断 49 { 50 bool vis=false;//是否 可看见 的标记 51 for(int j=0;j<m-1;j++) 52 { 53 if(visible(i,(x[j]+x[j+1])/2)) 54 { 55 vis=true;break; 56 } 57 } 58 if(vis) 59 if(i==0) 60 printf("%d",b[i].id); 61 else 62 printf(" %d",b[i].id); 63 } 64 printf(" "); 65 } 66 return 0; 67 }
思路:
将每个建筑的起始位置离散化,从小到大排序离散化的点;
将建筑按x从小到大排,x相同处按y从小到大排列;
按自定义的顺序从小到大遍历建筑,在每个离散化的两点间判断有没有该建筑,该建筑是否可见。
注意点:
1.输出的格式,每输出一组数据空一行,最后一组数据没有空白行;
每组数据中,每个可见的建筑后有一个空格,最后一个建筑后没有空白格。
2.int m=unique(x,x+n)-x;//使用该函数后不会改变原来的x[]数组
unique是个伪去重,只是把相同的元素放到了不同元素的后面
unique函数得到的是x[]去重后的尾部元素后一个元素的地址,减去x后得到的是不重复元素的个数
int x[6]={0,1,1,2,3,3};
伪去重后{0,1,2,3,1,3};
unique(x,x+6);指向3后面的1的地址,将该地址减去x首元素的地址,得到的就是不重复元素的个数。