Given a matrix of profit where each row represents a worker and each column represents a job maximize the profit by assigning each worker to a specific job. It is only one employee per job and one job per employee. Even if each each could make $1000 dollars on job 1 they all could not be tasked with job 1. Each job will be assigned exactly ONCE and each employee will be assigned exactly ONCE. The matrix will be NxN. The entries will be positive integers. You must return the assignment in some reasonable form. For example this string: "0->1, 1->2, 2->0" would indicate that employee 0 is doing job 1 and employee 1 is doing job 2...To solve this I will use a recursive dynamic programming solution which would take O(n!) time but since this problems has LOTS of overlapping subproblems my memoization decorator can be used in this problem.
The idea behind the recursive solution is something like this:
- w is a list of workers
- w (subscript) i is the ith element in w
- w-w (subscript) n indicates removal of that element from the list
- The costOf function is the cost of assigning a worked to a specific jobId. It ends up being a lookup in the matrix in my case
Here is the code that I attempted to explain above. Good luck. It's not easy. But try banging your head against it for a while. There are also other ways to solve this problem. Some of them a lot faster because my solution uses a lot of recursion. I'll provide a list of other possible ways to solve it at the bottom.
#my modified memoization function to support list hashing (its a hack)
def mem(fn):
mem = {}
def mod(*args):
arg_list = []
for a in args:
try:
arg_list.append(tuple(a))
except:
arg_list.append(a)
key = hash(tuple(arg_list))
if mem.has_key(key):
return mem[key]
else:
val = fn(*args)
mem[key] = val
return val
return mod
def profitimize(matrix):
plist = range(len(matrix))
def costMapping(m):
tmp = 0
for k in m:
tmp += matrix[k][m[k]]
return tmp
@mem
def profit(people, jobId):
if len(people) == 0:
return {}
currCost = 0
mapping = {}
bestPerson = -1
for person in people:
indyCost = matrix[person][jobId]
newPeople = list(people)
newPeople.remove(person)
result = dict(profit(newPeople, jobId+1))
indyCost += costMapping(result)
if currCost < indyCost:
currCost = indyCost
mapping = result
bestPerson = person
mapping[bestPerson] = jobId
return mapping
return profit(plist, 0)
if __name__ == '__main__':
matrix4 = [[10,40,30,20],[20,30,20,10],[30,20,10,40],[40,10,40,30]]
matrix7 = [[10,40,30,20,50,90,64],
[20,30,20,10,50,9,23],
[30,20,10,40,50,12,23],
[40,10,40,30,50,60,73],
[40,10,40,10,50,50,12],
[40,10,40,10,50,1,65],
[40,10,40,10,50,1,12]]
matrix10 = [[10,40,30,20,1,50,12,60,13,25],
[20,30,20,10,6,12,64,24,63,12],
[30,20,10,40,6,75,23,86,12,45],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53]]
matrix10_2 = [[1,2,3,4,5,6,7,8,9,10],
[10,1,2,3,4,5,6,7,8,9],
[9,10,1,2,3,4,5,6,7,8],
[8,9,10,1,2,3,4,5,6,7],
[7,8,9,10,1,2,3,4,5,6],
[6,7,8,9,10,1,2,3,4,5],
[5,6,7,8,9,10,1,2,3,4],
[4,5,6,7,8,9,10,1,2,3],
[3,4,5,6,7,8,9,10,1,2],
[2,3,4,5,6,7,8,9,10,1]]
matrix2 = [[10,20],[10,1]]
result = profitimize(matrix10_2)
print result
def mem(fn):
mem = {}
def mod(*args):
arg_list = []
for a in args:
try:
arg_list.append(tuple(a))
except:
arg_list.append(a)
key = hash(tuple(arg_list))
if mem.has_key(key):
return mem[key]
else:
val = fn(*args)
mem[key] = val
return val
return mod
def profitimize(matrix):
plist = range(len(matrix))
def costMapping(m):
tmp = 0
for k in m:
tmp += matrix[k][m[k]]
return tmp
@mem
def profit(people, jobId):
if len(people) == 0:
return {}
currCost = 0
mapping = {}
bestPerson = -1
for person in people:
indyCost = matrix[person][jobId]
newPeople = list(people)
newPeople.remove(person)
result = dict(profit(newPeople, jobId+1))
indyCost += costMapping(result)
if currCost < indyCost:
currCost = indyCost
mapping = result
bestPerson = person
mapping[bestPerson] = jobId
return mapping
return profit(plist, 0)
if __name__ == '__main__':
matrix4 = [[10,40,30,20],[20,30,20,10],[30,20,10,40],[40,10,40,30]]
matrix7 = [[10,40,30,20,50,90,64],
[20,30,20,10,50,9,23],
[30,20,10,40,50,12,23],
[40,10,40,30,50,60,73],
[40,10,40,10,50,50,12],
[40,10,40,10,50,1,65],
[40,10,40,10,50,1,12]]
matrix10 = [[10,40,30,20,1,50,12,60,13,25],
[20,30,20,10,6,12,64,24,63,12],
[30,20,10,40,6,75,23,86,12,45],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53],
[40,10,40,30,1,36,12,64,12,53]]
matrix10_2 = [[1,2,3,4,5,6,7,8,9,10],
[10,1,2,3,4,5,6,7,8,9],
[9,10,1,2,3,4,5,6,7,8],
[8,9,10,1,2,3,4,5,6,7],
[7,8,9,10,1,2,3,4,5,6],
[6,7,8,9,10,1,2,3,4,5],
[5,6,7,8,9,10,1,2,3,4],
[4,5,6,7,8,9,10,1,2,3],
[3,4,5,6,7,8,9,10,1,2],
[2,3,4,5,6,7,8,9,10,1]]
matrix2 = [[10,20],[10,1]]
result = profitimize(matrix10_2)
print result
Couple of other techniques:
0 comments:
Post a Comment