题意
城市俯视图 给出坐标,长宽高, 求从南向北(朝着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;
}