Manhattan skyline problem

老师给的一道算法作业题,要求O(nlgn)实现,题目如下:

 

 

Suppose that you are given the exact locations and shapes of several rectangular
buildings in a city, and you wish to draw the skyline (in two dimensions) of these
buildings, eliminating hidden lines. Assume that the bottoms of all the buildings lie on
a fixed line. Building Bi is represented by a triple (Li, Hi, Ri), where Li denotes the left
x-coordinate, Ri denote the right x-coordinate of the building, and Hi denotes the
building’s height. A skyline is a list of x coordinates and the heights connecting them
arranged in order from left to right. For example, the buildings in the figure 1 below
correspond to the following input (the numbers in boldface type are the heights):
(1, 7, 5), (9, 18, 12), (3, 3, 16), (15, 4, 18), (14, 13, 19).
Figure 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The skyline (in bold) is represented as follows (again, the numbers in boldface type
are the heights):
(1, 7, 5, 3, 9, 18, 12, 3, 14, 13, 19).
(a) Given a skyline of n buildings and another skyline of m buildings, show how to
compute the combined skyline for the m + n buildings in O(m + n) steps.
(b) Give a divide and conquer algorithm to compute the skyline of a given set of n
buildings. Your algorithm should run in O(n log n) steps.
(c) Write a program to implement your algorithms
.

 

 

 

 

 

解:第一问要求用O(m+n)的复杂度实现两个轮廓的合并,我们可以把轮廓用坐标数组表示出来,然后在坐标数组是进行操作,最后再用轮廓表示坐标数组。示例如下:

     假设第一个轮廓线数组为s1[1,5,3,7,5,4,7]

          第二个轮廓数组为s2[2,9,6,3,9]

那么我们可以用一个大小为9的数组来表示这两个轮廓(数组的下标代表坐标系下的横坐标),有

               ss1[5,5,7,7,7,4,4,0,0] 

               ss2[0,9,9,9,9,9,3,3,3]

为了编程方便以及和坐标系的对应我们假设这两个数组的下标都是从1开始的。根据题目的要求,可以通过比较ss1和ss2数组得到所求轮廓线的坐标数组ss3[5,9,9,9,9,9,4,3,3],最后我们需要做的就是把坐标数组ss3转化为轮廓线数组s3[1,5,2,9,6,4,7,3,9]。

程序清单如下:#include void main() { cout<<"请输入两个skyline数组的长度:"<>m>>n; int *s1=new int[m]; int *s2=new int[n]; int i=0; cout<<"请输入第一个skyline:"<>s1[i]; cout<<"请输入第二个skyline:"<>s2[i]; int length; if(s1[m-1]>s2[n-1]) length=s1[m-1]; else length=s2[n-1]; int *ss1=new int[length+1]; int *ss2=new int[length+1]; for(i=0;i<=length;i++) ss1[i]=ss2[i]=0; i=1; while(i=s1[k]&&i<=s1[k+2]) { if(i==s1[k+2]) { if(k+2==m-1) { ss1[i]=s1[k+1]; i++; } else { ss1[i]=((s1[k+1])>(s1[k+3]))?(s1[k+1]):(s1[k+3]); i++; } } else { ss1[i]=s1[k+1]; i++; } } k+=2; } i=1; while(i=s2[k]&&i<=s2[k+2]) { if(i==s2[k+2]) { if(k+2==n-1) { ss2[i]=s2[k+1]; i++; } else { ss2[i]=((s2[k+1])>(s2[k+3]))?(s2[k+1]):(s2[k+3]); i++; } } else { ss2[i]=s2[k+1]; i++; } } k+=2; } for(i=1;i<=length;i++) ss1[i]=(ss1[i]>ss2[i])?(ss1[i]):(ss2[i]);//ss1[]中存放的最终的坐标数组 for(i=1;i<=length;i++) cout<length) newskyline[j+2]=i-1; j+=2; } for(i=0;i

 

 

 

第二问要求给定n个建筑物各自的坐标,求出它们总体的轮廓线。要求时间复杂度为O(nlgn),并用分治算法,有了第一问的基础,再借鉴归并排序的算法思想,不难得出算法。只是在设计分治算法的时候怎么设计数据结构才能实现递归函数要好好思考。这里我把轮廓线当做一个结构体,如下:

typedef struct skyline

{

         int skylinenum;

         int sky[MAXNUM];

}*sky;

递归函数的参数为轮廓线数组s[],数组的起始下标和结束下标m,n。具体实现见代码清单:

#include #define MAXNUM 30 typedef struct skyline { int skylinenum; int sky[MAXNUM]; }*pskyline; void Merge_skyline(skyline s[],int m,int n) { int length,i,k,j; if((s[m].sky[s[m].skylinenum-1])>(s[n].sky[s[n].skylinenum-1])) length=s[m].sky[s[m].skylinenum-1]; else length=s[n].sky[s[n].skylinenum-1]; int *ss1=new int[length+1]; int *ss2=new int[length+1]; for(i=0;i<=length;i++) ss1[i]=ss2[2]=0; i=1; while(i=s[m].sky[k]&&i<=s[m].sky[k+2]) { if(i==s[m].sky[k+2]) { if(k+2==(s[m].skylinenum-1)) { ss1[i]=s[m].sky[k+1]; i++; } else { ss1[i]=((s[m].sky[k+1])>(s[m].sky[k+3]))?(s[m].sky[k+1]):(s[m].sky[k+3]); i++; } } else { ss1[i]=s[m].sky[k+1]; i++; } } k+=2; } i=1; while(i=s[n].sky[k]&&i<=s[n].sky[k+2]) { if(i==s[n].sky[k+2]) { if(k+2==(s[n].skylinenum-1)) { ss2[i]=s[n].sky[k+1]; i++; } else { ss2[i]=((s[n].sky[k+1])>(s[n].sky[k+3]))?(s[n].sky[k+1]):(s[n].sky[k+3]); i++; } } else { ss2[i]=s[n].sky[k+1]; i++; } } k+=2; } for(i=1;i<=length;i++) ss1[i]=(ss1[i]>ss2[i])?(ss1[i]):(ss2[i]);//ss1[]中存放的最终的坐标数组 //把坐标数组转换为skyline int newskylinenum=0; for(i=1;i<=length;i++) if(ss1[i-1]!=ss1[i]) newskylinenum++; newskylinenum=2*newskylinenum+1; int *newskyline=new int[newskylinenum]; i=1; while(ss1[i]==0) i++; j=0; while(i<=length&&jlength) newskyline[j+2]=i-1; j+=2; } s[m].skylinenum=newskylinenum; for(i=0;i>n; skyline *s=new skyline[n]; cout<<"请按照(左边界 高度 右边界)的格式依次输入各个建筑物:"<>s[i].sky[j]; } Make_skyline(s,0,n-1); cout<<"这些建筑的轮廓线是:"<

 

 

 

你可能感兴趣的:(Manhattan skyline problem)