Guest User

2d House Robber : Dynamic Programming

a guest
Dec 17th, 2015
769
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.86 KB | None | 0 0
  1. import sys
  2. from itertools import product
  3. import operator
  4. from io import StringIO
  5.  
  6. """
  7. The 2D House Robber is : Given a City laid out on a grid, there are R rows
  8. of houses and C columns of houses. Each house is known to contain some amount
  9. of valuables totaling v_ij. Your task is to rob as many houses as possible
  10. to maximize the amount of loot. However there is a security system in place
  11. and if you rob two adjacent houses an alarm will go off
  12. Find the optimum set of non-adjacent houses to rob.
  13.    e.g.:  Houses:  alignment:
  14.          10 20 10     0  1  0
  15.          20 30 20 =>  1  0  1
  16.          10 20 10     0  1  0
  17.        This alignment results in the maximum of 80.
  18.  
  19. This solution is optimized to about O(N*φ^N) for an NxN matrix
  20.  
  21. """
  22. def read_input(stream):
  23.     """ read an input file like object
  24.  
  25.    first line of input contains two integers, R and C specifying the
  26.    number of rows and columns. This is followed by R rows of C integers
  27.    specifying the input matrix
  28.    """
  29.     R,C = map(int,stream.readline().strip().split())
  30.     tbl = [ list(map(int,line.strip().split()))[:C] for line in stream ]
  31.     return R,C,tbl
  32.  
  33. def compute_alignments(n):
  34.     """ return all valid alignments for a single row
  35.  
  36.    an alignment is valid if there are no adjacent 1's
  37.  
  38.    for a given input n, there are approximately 1.6^(n+1) valid alignments
  39.    (which is equivalent to the n+1'th Fibonacci number.)
  40.    """
  41.     for ali in product([0,1,],repeat=n):
  42.         for i in range(1,n):
  43.             if ali[i]&ali[i-1]:
  44.                 break
  45.         else:
  46.             yield ali
  47.  
  48. def compute_alignment_pairs(alignments_all):
  49.     """ return a mapping for compatible alignments for each alignment
  50.  
  51.    alignments are compatible, if when stacked on top of each other (in 2d)
  52.    there is no 1 at the same x position.
  53.    """
  54.     alipairs = [ set() for i in range(len(alignments_all)) ]
  55.     for a,ali1 in enumerate(alignments_all):
  56.         for b,ali2 in enumerate(alignments_all):
  57.             if any( x&y for x,y in zip(ali1,ali2)):
  58.                 continue
  59.             alipairs[a].add(b)
  60.     return alipairs
  61.  
  62. def solve(R,C,tbl,alignments_all,alignment_pairs):
  63.     """
  64.    Solve the 2D House Robber problem by comparing all possible
  65.    valid alignments for each row in the matrix.
  66.    """
  67.     N = len(alignments_all)
  68.     # small optimization for dot product (remove reference to global variables)
  69.     dot = lambda a,b,sum=sum,map=map,mul=operator.mul : sum(map(mul, a, b))
  70.     # d_prev / d_next are the score given alignment i for a given row.
  71.     d_prev = [ dot(tbl[0],ali) for ali in alignments_all ]
  72.     # p is the predecessors array
  73.     p =[ None,]*R
  74.     p[0] = [0,]*N
  75.     for i in range(1,R):
  76.         values = [ dot(tbl[i],ali) for ali in alignments_all ]
  77.         d_next = [0,] * N
  78.         p[i]   = [0,] * N # new array for predecessors for this row
  79.  
  80.         for a in range(N):
  81.             for b in alignment_pairs[a]:
  82.                 value = d_prev[a]+values[b]
  83.                 if value > d_next[b]:
  84.                     d_next[b] = value
  85.                     p[i][b] = a
  86.         d_prev = d_next
  87.  
  88.     # read back solutions for optimal alignment
  89.     value = max(d_prev)
  90.     index = d_prev.index(value)
  91.     ali = []
  92.     for i in reversed(range(0,R)):
  93.         ali.insert(0,alignments_all[index])
  94.         index = p[i][index]
  95.     return value,ali
  96.  
  97. def main():
  98.  
  99.     string_input="""3 3
  100. 10 20 10
  101. 20 30 20
  102. 10 20 10
  103. """
  104.     #R,C,tbl = read_input(sys.stdin)
  105.     R,C,tbl = read_input(StringIO(string_input))
  106.  
  107.     alignments_all = list(compute_alignments(C))
  108.     alignment_pairs = compute_alignment_pairs(alignments_all)
  109.     value_max,alignment = solve(R,C,tbl,alignments_all,alignment_pairs)
  110.     for row in tbl:
  111.         print(row)
  112.     print("max:",value_max)
  113.     for row in alignment:
  114.         print(row)
  115.  
  116. if __name__ == '__main__':
  117.     main()
Advertisement
Add Comment
Please, Sign In to add comment