Advertisement
Guest User

Indian Computing 2015, afternoon problem 2

a guest
Oct 2nd, 2015
335
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.58 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3.  
  4. '''Solver for problem 2 of http://www.iarcs.org.in/inoi/2015/zco2015/zco2015-afternoon.pdf.'''
  5.  
  6.  
  7. import random
  8.  
  9.  
  10. SIZE = (100000, 500)
  11.  
  12. def random_points(N):
  13.     '''Return a list of N random points (tuples x,y).'''
  14.     points = set()
  15.     for dummy_i in range(N):
  16.         insertion_todo = True
  17.         while insertion_todo:
  18.             point = (random.randint(1, SIZE[0]-1), random.randint(1, SIZE[1]-1))
  19.             if not point in points:
  20.                 points.add(point)
  21.                 insertion_todo = False
  22.     return list(points)
  23.  
  24.  
  25. def remove_same_x_value(points):
  26.     '''
  27.    Return a list where points with identical x value and higher y are removed
  28.    and the list is sorted by x value (descending).
  29.    '''
  30.     # sort by x and then y value; use pythons dictionary ordering
  31.     ordered = sorted(points, reverse=True)
  32.     # create new list with first element already included
  33.     cleaned = [ordered[0]]
  34.     for point in ordered:
  35.         if point[0] == cleaned[-1][0]:
  36.             # if the current point has the same x value, use its lower y value
  37.             cleaned[-1] = point
  38.         else:
  39.             # otherwise (new x value), add it
  40.             cleaned.append(point)
  41.     return cleaned
  42.  
  43.  
  44. def max_rectangle(points):
  45.     '''
  46.    Return the largest possible rectangle area from a list of points.
  47.  
  48.    Algorithm: Try to use points from right to left in the rectangle.
  49.        - If there are more points for one x value, only the one with lowest y
  50.          value is used.
  51.        - First check the extreme x points; most right and most left, spanning
  52.          a rectangle to the resp. limits.
  53.        - Then go the the rightmost point and try to build a rectangle including it.
  54.          There are two possibilities:
  55.            - this point is on a horizontal edge
  56.              Find its two neighbours, left and right, that have lower y value,
  57.              as points on the left resp. right edge.  If there is no
  58.              left/right neighbour, use the end of the space.
  59.            - this point is on a vertical edge
  60.              Find the next-left point, use limit of the space as horizontal
  61.              edge.
  62.    '''
  63.     # order and clean (remove points with same x value) points
  64.     clean_points = remove_same_x_value(points)
  65.  
  66.     # compute area right of most-right point
  67.     max_x = clean_points[0]
  68.     area_right = (SIZE[0] - max_x[0]) * SIZE[1]
  69.     # compute area left of most-left point
  70.     min_x = clean_points[-1]
  71.     area_left = min_x[0] * SIZE[1]
  72.     max_area = max(area_right, area_left)
  73.  
  74.     #print('area left: {:.2e}, right: {:.2e}'.format(area_left, area_right))
  75.  
  76.     # now try to include each point in the rectangle
  77.     for index in (range(len(clean_points))):
  78.  
  79.         # use point as on horizontal edge
  80.         upper_edge_index = index
  81.         height = clean_points[upper_edge_index][1]
  82.         left = None
  83.         right = None
  84.         # search left neighbour (increasing index)
  85.         for left_edge_index in range(upper_edge_index, len(clean_points)):
  86.             if clean_points[left_edge_index][1] < height:
  87.                 left = clean_points[left_edge_index][0]
  88.                 break
  89.         # if unable to find a left border, use the border of the area
  90.         if left is None:
  91.             left = 0
  92.         # search right neighbour:
  93.         for right_edge_index in range(upper_edge_index-1, 0-1, -1):
  94.             if clean_points[right_edge_index][1] < height:
  95.                 right = clean_points[right_edge_index][0]
  96.                 break
  97.         # if unable to find a right border, use the border of the area
  98.         if right is None:
  99.             right = SIZE[0]
  100.         # compute area of this found rectangle
  101.         area = (right - left) * height
  102.         #print('Found bounded rectangle between x {}, {} and height {}; area {:.2e}'.format(left, right, height, area))
  103.  
  104.         if area > max_area:
  105.             max_area = area
  106.  
  107.  
  108.         # use point as on vertical edge
  109.         right_edge = clean_points[index][0]
  110.         # next vertical edge is simply next point
  111.         try:
  112.             left_edge = clean_points[index + 1][0]
  113.             area = (right_edge - left_edge) * SIZE[1]
  114.  
  115.             #print('Found open rectangle between x {}, {}; area {:.2e}'.format(left_edge, right_edge, area))
  116.  
  117.             if area > max_area:
  118.                 max_area = area
  119.  
  120.         except IndexError:
  121.             # no next edge; this is the leftmost-case from above...
  122.             pass
  123.  
  124.  
  125.  
  126.     return max_area
  127.  
  128.  
  129.  
  130. # actual program
  131.  
  132. def run_random(N):
  133.     print('Running for {} points (area {})'.format(
  134.         N, max_rectangle(random_points(N))))
  135.  
  136. def run_random_silent(N):
  137.     max_rectangle(random_points(N))
  138.  
  139. # Run from command line with first argument as number of points to create.
  140. import sys
  141. run_random(int(sys.argv[1]))
  142.  
  143. # Simple tests
  144. def test_max_rectangle():
  145.     assert max_rectangle([(1, 4), (2, 3), (3, 2), (5, 1), (5, 2)]) == 49997500, 'test case from problem'
  146.     assert max_rectangle([(90000, 4)]) == 90000 * SIZE[1], 'biggest rectangle to the left'
  147.     print('test')
  148.     assert max_rectangle([(3, 25), (SIZE[0] - 10, 13)]) == (SIZE[0] - 10 - 3) * SIZE[1], 'biggest rectangle open in middle'
  149.     assert max_rectangle([(5, 90), (45000, 428), (99000, 33)]) == (99000 - 5) * 428, 'biggest rectangle bounded in middle'
  150.  
  151. def test_remove_same_x_value():
  152.     assert remove_same_x_value([(3,3), (3,4)]) == [(3,3)], 'remove x values 1'
  153.     assert remove_same_x_value([(2,1), (2,5), (3,5), (3,4)]) == [(3,4), (2,1)], 'remove x values 2'
  154.  
  155. def tests():
  156.     test_max_rectangle()
  157.     test_remove_same_x_value()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement