{ ACM International Collegiate Programming Contest Central European Regional Contest 2000 Problem B - The Bulk Martin Kacer } Program Volume; Const MAX_POINTS = 512; MAX_POLYGONS = 512; Type TPoint = Record X, Y, Z : Integer; End; Type TPolygon = Record N : Integer; P: Array [1..MAX_POINTS] of TPoint; End; Var TaskCnt, TaskNum : Integer; Polys : Array [1..MAX_POLYGONS] of TPolygon; PolysCnt, PolysXY : Integer; I, J : Integer; SqInside : TPoint; TopSide : Boolean; SumVolume : Integer; { reads polygon into `Poly' and returns true if it is in XY direction } Function ReadPolygon (Var Poly : TPolygon) : Boolean; Var I : Integer; Begin ReadPolygon:= true; Read (Poly.N); For I:= 1 to Poly.N do Begin Read (Poly.P[I].X, Poly.P[I].Y, Poly.P[I].Z); if (Poly.P[I].Z <> Poly.P[1].Z) then ReadPolygon:= false; End; ReadLn; End; { ReadPolygon } { computes area of an XY polygon } Function PolygonXYArea (Var Poly : TPolygon) : Integer; Var I, I1 : Integer; Area : Integer; Begin Area:= 0; For I:= 1 to Poly.N do Begin I1:= I - 1; if (I1 = 0) then I1:= Poly.N; Area:= Area + Poly.P[I].Y * (Poly.P[I].X - Poly.P[I1].X); End; If (Area < 0) then PolygonXYArea:= 0 - Area else PolygonXYArea:= Area; End; { PolygonXYArea } { returns one square inside a polygon; square is (X,Y,Z)-(X+1,Y+1,Z) } Procedure SquareInsideXYPolygon (Var Poly : TPolygon; Var Sq : TPoint); Var MinX, MinY : Integer; I, I1 : Integer; Begin MinX:= Poly.P[1].X + 1; For I:= 1 to Poly.N do Begin I1:= I - 1; if (I1 = 0) then I1:= Poly.N; If (Poly.P[I].X = Poly.P[I1].X) and (Poly.P[I].X < MinX) then Begin MinX:= Poly.P[I].X; MinY:= Poly.P[I].Y; if (MinY > Poly.P[I1].Y) then MinY:= Poly.P[I1].Y; End; End; Sq.X:= MinX; Sq.Y:= MinY; Sq.Z:= Poly.P[1].Z; End; { SquareInXYPolygon } { finds out if the square is inside the polygon } Function IsInsideXYPolygon (Var Poly : TPolygon; Sq : TPoint) : Boolean; Var I, I1 : Integer; Y1, Y2 : Integer; Ret : Boolean; Begin Ret:= false; For I:= 1 to Poly.N do Begin I1:= I - 1; if (I1 = 0) then I1:= Poly.N; If (Poly.P[I].X = Poly.P[I1].X) and (Poly.P[I].X <= Sq.X) then Begin If (Poly.P[I].Y < Poly.P[I1].Y) then Begin Y1:= Poly.P[I].Y; Y2:= Poly.P[I1].Y; End else Begin Y1:= Poly.P[I1].Y; Y2:= Poly.P[I].Y; End; If (Y1 <= Sq.Y) and (Sq.Y < Y2) then Ret:= not Ret; End; End; IsInsideXYPolygon:= Ret; End; { IsInsideXYPolygon } Begin Readln (TaskCnt); For TaskNum:= 1 to TaskCnt do Begin ReadLn (PolysCnt); PolysXY:= 1; For I:= 1 to PolysCnt do If ( ReadPolygon (Polys[PolysXY]) ) then PolysXY:= PolysXY + 1; PolysXY:= PolysXY - 1; SumVolume:= 0; For I:= 1 to PolysXY do Begin TopSide:= false; SquareInsideXYPolygon (Polys[I], SqInside); For J:= 1 to PolysXY do If (Polys[J].P[1].Z < Polys[I].P[1].Z) then If (IsInsideXYPolygon (Polys[J], SqInside)) then TopSide:= not TopSide; {WriteLn ('POLY: area=', PolygonXYArea (Polys[I]), ', z=', Polys[I].P[1].Z, ', top=', TopSide, ', square=(', SqInside.X,',', SqInside.Y,',',SqInside.Z,')');} If (TopSide) then SumVolume:= SumVolume + Polys[I].P[1].Z * PolygonXYArea (Polys[I]) else SumVolume:= SumVolume - Polys[I].P[1].Z * PolygonXYArea (Polys[I]); End; WriteLn ('The bulk is composed of ', SumVolume, ' units.'); End; End.