书上的思路(离散化):把所有x坐标排序去重,则任意两个相邻x坐标形成的区间具有相同属性,一个区间要么完全可见,要么完全不可见。这样,只需在这个区间里任选一个点(例如中点),就能判断出一个建筑物是否在整个区间内可见。如何判断一个建筑物是否在某个x坐标处可见呢?首先,建筑物的坐标中必须包含这个x坐标,其次,建筑物南边不能有另外一个建筑物也包含这个x坐标,并且不比它矮。代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100 + 5;
struct building{
int id;
double x,y,w,d,h;
}b[maxn];
int n;
double x[maxn*2];
int cmp(building a,building b){
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
bool cover(int i,double mx){
return b[i].x <= mx && b[i].x+b[i].w >= mx;
}
//判断建筑物i在x=mx处是否可见
bool visible(int i,double mx){
if(!cover(i,mx)) return false;
for(int k = 0;k < n;k++) // 注意不是按y排序 所以要一直循环到最后
if(b[k].y < b[i].y && b[k].h >= b[i].h && cover(k,mx)) return false;
return true;
}
int main(){
int kase = 0;
while(scanf("%d",&n) && n){
for(int i = 0;i < n;i++){
scanf("%lf%lf%lf%lf%lf",&b[i].x,&b[i].y,&b[i].w,&b[i].d,&b[i].h);
x[i*2] = b[i].x;
x[i*2+1] = b[i].x + b[i].w;
b[i].id = i+1;
}
sort(b,b+n,cmp);
sort(x,x+n*2);
int m = unique(x,x+n*2) - x; //x坐标排序后去重,得到m个坐标
if(kase++) putchar('\n');
printf("For map #%d, the visible buildings are numbered as follows:\n%d",kase,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)){ vis = true;break;}
if(vis) printf(" %d",b[i].id);
}
putchar('\n');
}
return 0;
}
另外一种思路(枚举加区间覆盖):
先枚举每个建筑物,把可能覆盖的建筑物保存下来,然后就变成一个区间覆盖问题,判断能完全覆盖的就是会被挡住。我更喜欢这个思路哈哈,代码如下:#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 105;
struct build{
int id,x,y,w,d,h;
}city[maxn],save[maxn];
int n;
int cmp(build a,build b){
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
bool judge(build a){
int cnt = 0;
for(int i = 0;i < n;i++){
build b = city[i];
if(b.y >= a.y) continue;
if(b.h < a.h) continue;
if(b.x >= a.x + a.w || b.x + b.w <= a.x) continue;
save[cnt++] = b;
}
if(!cnt) return true;
int t = a.x;
for(int i = 0;i < cnt;i++){
if(t < save[i].x) return true;
t = max(t,save[i].x + save[i].w);
}
if(t < a.x + a.w) return true;
return false;
}
int main(){
int kase = 0;
while(scanf("%d",&n) && n){
for(int i = 0;i < n;i++){
scanf("%d%d%d%d%d",&city[i].x,&city[i].y,&city[i].w,&city[i].d,&city[i].h);
city[i].id = i + 1;
}
sort(city,city + n,cmp);
if(kase++) putchar('\n');
printf("For map #%d, the visible buildings are numbered as follows:\n%d",kase,city[0].id);
for(int i = 1;i < n;i++){
if(judge(city[i])) printf(" %d",city[i].id);
}
putchar('\n');
}
return 0;
}