// RoadConstruction.cpp : Defines the entry point for the console application.

//

// by Adrian Dale 15/12/2008

// Solution to the IEEE Challenge 2008 - Road Construction

// http://www.ieee.org/portal/cms_docs_iportals/iportals/membership/students/scholarshipsawardscontests/IEEEXtreme2008_Competition_Booklet.pdf

//

// This code works by first parsing the input data into a minimal set of constraints

// needed to solve the problem. That is, we only need to take into account the houses

// that are closest to each side of the road. So, for each row we store the widest allowed

// distance from the road to the left of the road and to the right of the road.

//

// We then use a recursive function to try out all possible starting positions of

// each parcel of land to see what area of land they give.

// We record the maximum area once all possible parcel subdivisions have been tested

// and output it as the puzzle answer.

 

#include "stdafx.h"

#include <iostream>

#include <vector>

#include <algorithm>

 

using namespace std;

 

// Data structures to hold the road map data

// We don't need to hold a 2D array, since some of the house data is likely

// to be redundant.

// All we need to know for each row is the smallest possible rectangle we

// could fit on that row

struct BoardRow

{

      int Left;

      int Right;

};

 

vector<BoardRow> Board;

typedef vector<BoardRow>::iterator BoardIter;

 

// We get given this number - the number of parcels of land we must divide the

// map into

int Parcels = 0;

 

// We get given this number - Height is how long the road is

int Height = 0;

int Width = 0;

 

// We need this to store the maximum area so far as we go through our recursive

// algorithm.

int MaxParcelArea = 0;

 

// ReadInput reads the challenge parameters from stdin.

// See challenge for input format.

// Note that this function assumes the input data is valid.

// Not a great assumption but should do for this quick and dirty code.

void ReadInput()

{

      int Houses = 0;

 

      // Height of the board comes first in the input

      cin >> Height;

      // We'll have a row for each square of height

      Board.resize(Height);

 

      // Next input value is width

      cin >> Width;

      // Width of map marks the min and max possible widths of a rectangle

      // at each y coordinate. Note that a Width of n is equivalent to a house at n+1

      // Adding in the houses will narrow these constraints

      for( BoardIter it=Board.begin(); it != Board.end(); ++it )

      {

            it->Left = -1 * (Width+1);

            it->Right = Width+1;

      }

 

      // Read in count of number of parcels of land

      cin >> Parcels;

 

      // Read in the number of houses - we use this to tell us how many

      // sets of input coordinates to expect

      cin >> Houses;

 

      for( int i=0; i<Houses; ++i )

      {

            int HouseX = 0;

            int HouseY = 0;

            cin >> HouseY;

            cin >> HouseX;

 

            // Decrement HouseY so we can use it as an array index.

            // For some reason the rows seem to

            // be numbered from 1 in the input.

            --HouseY;

 

            if ( HouseX < 0 )

            {

                  // Only update the board with the house coordinates if it narrows the

                  // constraints

                  if ( HouseX > Board[HouseY].Left)

                        Board[HouseY].Left = HouseX;

            }

            else

            {

                  if ( HouseX < Board[HouseY].Right)

                        Board[HouseY].Right = HouseX;

            }

      }

}

 

// GetParcelArea returns the area covered by the passed in

// allocation of the parcels

int GetParcelArea( vector<int> &ParcelList )

{

      int TotalParcelArea = 0;

 

      // Parcel list comes in as a vector of starting positions

      // for each parcel, numbered from 0.

      // Go through each parcel in the list and add its area to the

      // TotalParcelArea

      for ( int parcelNo=0; parcelNo<ParcelList.size(); ++parcelNo )

      {

            // We're given the start row of each parcel.

            // The end row is the one before the start of the next parcel,

            // or the top of the map for the last parcel

            int ParcelStart = ParcelList[parcelNo];

            int ParcelEnd;

            if ( parcelNo < ParcelList.size() - 1 )

                  ParcelEnd = ParcelList[parcelNo+1];

            else

                  ParcelEnd = Height;

 

            // Work out the widest rectancle we can fit in this parcel's

            // range of rows by looping through the constraints for each

            // row that makes up the parcel

            int MaxLeft = -1*(Width+1);

            int MinRight = Width+1;

            for( int i=ParcelStart; i<ParcelEnd; ++i )

            {

                  if ( Board[i].Left > MaxLeft)

                        MaxLeft = Board[i].Left;

 

                  if ( Board[i].Right < MinRight)

                        MinRight = Board[i].Right;

            }

 

            // Very simple formula for area of a rectangle!

            int ParcelArea = (MinRight - MaxLeft - 1) * (ParcelEnd - ParcelStart);

 

            TotalParcelArea += ParcelArea;

      }

 

      return TotalParcelArea;

}

 

// This function recursively tries all possible parcel

// sizes into the parcel list

void TryParcelList( vector<int> ParcelList, int parcelNo )

{

      if ( parcelNo == Parcels )

      {

            // We've filled our list of guesses, so try it out

            int GuessArea = GetParcelArea( ParcelList );

 

            if ( GuessArea > MaxParcelArea )

                  MaxParcelArea = GuessArea;

      }

      else

      {

            // Still some more parcels to allocate, so call this fn recursively

            // for each possible parcel left at this level, starting from

            // where the previous ones left off, and finishing with enough room for

            // all remaining parcels of minimum size

            for (int i=ParcelList[parcelNo-1] + 1; i <= Height - Parcels + parcelNo; ++i )

            {

                  ParcelList[parcelNo] = i;

                  TryParcelList( ParcelList, parcelNo + 1 );

            }

      }

}

 

// This function kicks off the recursive search for the best possible subdivision

// of the map into parcels.

int GetMaxParcelArea()

{

      vector<int> ParcelList;

      ParcelList.resize(Parcels);

     

      MaxParcelArea = 0;

 

      // First piece always starts at zero

      ParcelList[0] = 0;

 

      // Kick off the recursive function

      TryParcelList( ParcelList, 1 );

 

      return MaxParcelArea;

}

 

int _tmain(int argc, _TCHAR* argv[])

{

      ReadInput();

     

      cout << GetMaxParcelArea() << endl;

     

      return 0;

}