program skyline_problem; { Programmed by: Svetlana Kryukova Programmed on: May 19, 1993 } {-------------------------------------------------------------------------} const MaxR = 20; { maximum number of rectangleSkyline } MaxSkylineSize = 79; { 4*MaxR - 1, maximum size of the Skyline } type skyline = array [1..MaxSkylineSize] of integer; Rectangle = array [1..3] of integer; Skylines = array [1..MaxR] of Rectangle; problem_t = record Points : Skylines; size : integer; end; solution_t = record Points : skyline; size : integer; end; {-------------------------------------------------------------------------} function Base_Case(Buildings: problem_t):boolean; { Precondition: Buildings is some problem, such that Buildings.size >= 0 and Buildings.Points is an array of buildings presented by the array of their coordinates in the form (x1 y1 x2 y2 ... xn) } { Postcondition: return value Base_Case is true if and only if Buildings is a base-case problem (Buildings.size = 1) } begin Base_Case := (Buildings.size = 1); end; {-------------------------------------------------------------------------} procedure Find_Base_Case_Solution(var Buildings: problem_t; var Skyline : solution_t); { Precondition: Buildings is a base-case problem, such that Buildings.size = 1 } { Postcondition: Skyline is a correct solution to the problem Buildings such that Skyline.Points = Buildings.Points[1] } var i : integer; begin for i := 1 to 3 do Skyline.Points[i] := Buildings.Points[1][i]; Skyline.size := 3; end; {-------------------------------------------------------------------------} procedure Split(var Buildings, LeftBuildings, RightBuildings: problem_t); { Precondition : Buildings is an array of buildings, presented by an array of coordinates. Building.size > 1 Postcondition: LeftBuildings and RightBuildings are arrays of buidings and together they are some permutation of the array Buildings and |LeftBuildings.size - RightBuildings.size| <= 1 } var i : integer; begin LeftBuildings.size := Buildings.size div 2; RightBuildings.size := Buildings.size - Buildings.size div 2; {Assertion : |LeftBuildings.size - RightBuildings.size| <= 1 } for i := 1 to LeftBuildings.size do LeftBuildings.Points[i] := Buildings.Points[i]; { Assertion: for all i such that 1 <= i <= LeftBuildings.size LeftBuildings[i] = Buildings[i] } for i := LeftBuildings.size + 1 to Buildings.size do RightBuildings.Points[i - LeftBuildings.size] := Buildings.Points[i]; { Assertion: for all i such that 1 <= i <= RightBuildings.size RightBuildings[i] = Buildings[i]+LeftBuildings.size } end; {-------------------------------------------------------------------------} procedure Merge(var LeftSkyline, RightSkyline, Skyline : solution_t); { Precondition : LeftSkyline and RightSkyline are two arrays of coordinates presenting two skyline, Postcondition: Skyline is a common skyline for two LeftSkyline and RightSkyline } var i, { pointSkyline to the first unprocessed abscissa of skyline 1 } j, { pointSkyline to the first unprocessed abcsissa of skyline 2 } m: integer; k : 1..2; CurHeightLeftSkyline, CurHeightRightSkyline, CurHeight: integer; begin i := 1; j := 1; Skyline.size := 0; CurHeightLeftSkyline := 0; CurHeightRightSkyline := 0; CurHeight := 0; k := 1; while (i <= LeftSkyline.size) and (j <= RightSkyline.size) do if LeftSkyline.Points[i] < RightSkyline.Points[j] then begin if i < LeftSkyline.size then CurHeightLeftSkyline := LeftSkyline.Points[i+1] else CurHeightLeftSkyline := 0; if k = 1 then if CurHeightLeftSkyline >= CurHeightRightSkyline then begin Skyline.Points[Skyline.size+1] := LeftSkyline.Points[i]; Skyline.Points[Skyline.size+2] := CurHeightLeftSkyline; CurHeight := CurHeightLeftSkyline; Skyline.size := Skyline.size + 2; end else begin k := 2; if CurHeightRightSkyline < CurHeight then begin Skyline.Points[Skyline.size+1] := LeftSkyline.Points[i]; Skyline.Points[Skyline.size+2] := CurHeightRightSkyline; CurHeight := CurHeightRightSkyline; Skyline.size := Skyline.size + 2; end; end else if CurHeightLeftSkyline > CurHeight then begin Skyline.Points[Skyline.size+1] := LeftSkyline.Points[i]; Skyline.Points[Skyline.size+2] := CurHeightLeftSkyline; CurHeight := CurHeightLeftSkyline; k := 1; Skyline.size := Skyline.size + 2; end; i := i + 2; end { if LeftSkyline.Points[i] < RightSkyline.Points[j] } else if LeftSkyline.Points[i] > RightSkyline.Points[j] then begin if j < RightSkyline.size then CurHeightRightSkyline := RightSkyline.Points[j+1] else CurHeightRightSkyline := 0; if k = 2 then if CurHeightRightSkyline >= CurHeightLeftSkyline then begin Skyline.Points[Skyline.size+1] := RightSkyline.Points[j]; Skyline.Points[Skyline.size+2] := CurHeightRightSkyline; CurHeight := CurHeightRightSkyline; Skyline.size := Skyline.size + 2; end else begin k := 1; if CurHeightLeftSkyline < CurHeight then begin Skyline.Points[Skyline.size+1] := RightSkyline.Points[j]; Skyline.Points[Skyline.size+2] := CurHeightLeftSkyline; CurHeight := CurHeightLeftSkyline; Skyline.size := Skyline.size + 2; end; end else if CurHeightRightSkyline > CurHeight then begin Skyline.Points[Skyline.size+1] := RightSkyline.Points[j]; Skyline.Points[Skyline.size+2] := CurHeightRightSkyline; CurHeight := CurHeightRightSkyline; k := 2; Skyline.size := Skyline.size + 2; end; j := j + 2; end { if LeftSkyline.Points[i] > RightSkyline.Points[j] } else begin if i < LeftSkyline.size then CurHeightLeftSkyline := LeftSkyline.Points[i+1] else CurHeightLeftSkyline := 0; if j < RightSkyline.size then CurHeightRightSkyline := RightSkyline.Points[j+1] else CurHeightRightSkyline := 0; if CurHeightLeftSkyline >= CurHeightRightSkyline then begin k := 1; if CurHeightLeftSkyline <> CurHeight then begin Skyline.Points[Skyline.size+1] := LeftSkyline.Points[i]; if (i<>LeftSkyline.size) or (j<>RightSkyline.size) then begin Skyline.Points[Skyline.size+2] := CurHeightLeftSkyline; Skyline.size := Skyline.size + 1 end; CurHeight := CurHeightLeftSkyline; Skyline.size := Skyline.size + 1; end; end else begin k := 2; if CurHeightRightSkyline <> CurHeight then begin Skyline.Points[Skyline.size+1] := RightSkyline.Points[j]; Skyline.Points[Skyline.size+2] := CurHeightRightSkyline; CurHeight := CurHeightRightSkyline; Skyline.size := Skyline.size + 2; end; end; i := i + 2; j := j + 2; end; for m := i to LeftSkyline.size do begin Skyline.Points[Skyline.size+1] := LeftSkyline.Points[m]; Skyline.size := Skyline.size + 1; end; for m := j to RightSkyline.size do begin Skyline.Points[Skyline.size+1] := RightSkyline.Points[m]; Skyline.size := Skyline.size + 1; end; end; {-------------------------------------------------------------------------} procedure Find_Skyline(var Buildings : problem_t; var Skyline : solution_t); var LeftBuildings, RightBuildings : problem_t; LeftSkyline, RightSkyline : solution_t; begin if Base_Case(Buildings) then Find_Base_Case_Solution(Buildings, Skyline) else begin Split(Buildings, LeftBuildings, RightBuildings); Find_Skyline(LeftBuildings, LeftSkyline); Find_Skyline(RightBuildings, RightSkyline); Merge(LeftSkyline, RightSkyline, Skyline); end; end; {-------------------------------------------------------------------------} procedure GetProblem(var Buildings : problem_t); var i, j : integer; begin write(output, ' Enter the number of buildings in the City: '); readln(input, Buildings.size); write(output, ' Enter only three coordinates for each building, x1 y x2, '); writeln (output, 'representing '); writeln (output, ' the building (x1,0),(x1,y),(x2,y) & (x2,0)'); writeln (output, ' (LIMITATIONS: x in [0..300], y in [0..170])'); writeln (output); for i := 1 to Buildings.size do begin write(output, ' Enter building#', i:1, ' coordinates: '); for j := 1 to 3 do read(input, Buildings.Points[i][j]); end; end; {-------------------------------------------------------------------------} procedure DisplayProblem (var Buildings: problem_t); var k : integer; begin writeln('=========================================='); writeln(' Problem is a collection of ', Buildings.size:0, ' builings :'); for k := 1 to Buildings.size do writeln(' Rectangle #', k:0, ' has coordinates : ', Buildings.Points[k][1]:0, ' ', Buildings.Points[k][2]:0, ' ', Buildings.Points[k][3]:0); end; {-------------------------------------------------------------------------} procedure DisplaySolution (var Skyline: solution_t); var k : integer; begin writeln('= = = = = = = = = = = = = = = = = = = = = '); writeln(' Solution is a skyline of size ', Skyline.size:0); for k := 1 to Skyline.size do if (k mod 2) = 1 then writeln(' x', ((k - 1)div 2 + 1):0, ' = ', Skyline.Points[k]:0) else writeln(' y', ((k-1) div 2 + 1):0, ' = ', Skyline.Points[k]:0); end; {-------------------------------------------------------------------------} procedure SolveOneProblem; var Buildings : problem_t; Skyline : solution_t; begin GetProblem(Buildings); DisplayProblem(Buildings); Find_Skyline(Buildings, Skyline); DisplaySolution(Skyline); end; {-------------------------------------------------------------------------} begin SolveOneProblem; end.