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: ');
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
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.