Skip to content

Commit bb29dc5

Browse files
adMenonpoyea
authored andcommitted
Bitmasking and DP added (#705)
1 parent 441b82a commit bb29dc5

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

dynamic_programming/bitmask.py

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
3+
This is a python implementation for questions involving task assignments between people.
4+
Here Bitmasking and DP are used for solving this.
5+
6+
Question :-
7+
We have N tasks and M people. Each person in M can do only certain of these tasks. Also a person can do only one task and a task is performed only by one person.
8+
Find the total no of ways in which the tasks can be distributed.
9+
10+
11+
"""
12+
from __future__ import print_function
13+
from collections import defaultdict
14+
15+
16+
class AssignmentUsingBitmask:
17+
def __init__(self,task_performed,total):
18+
19+
self.total_tasks = total #total no of tasks (N)
20+
21+
# DP table will have a dimension of (2^M)*N
22+
# initially all values are set to -1
23+
self.dp = [[-1 for i in range(total+1)] for j in range(2**len(task_performed))]
24+
25+
self.task = defaultdict(list) #stores the list of persons for each task
26+
27+
#finalmask is used to check if all persons are included by setting all bits to 1
28+
self.finalmask = (1<<len(task_performed)) - 1
29+
30+
31+
def CountWaysUtil(self,mask,taskno):
32+
33+
# if mask == self.finalmask all persons are distributed tasks, return 1
34+
if mask == self.finalmask:
35+
return 1
36+
37+
#if not everyone gets the task and no more tasks are available, return 0
38+
if taskno > self.total_tasks:
39+
return 0
40+
41+
#if case already considered
42+
if self.dp[mask][taskno]!=-1:
43+
return self.dp[mask][taskno]
44+
45+
# Number of ways when we dont this task in the arrangement
46+
total_ways_util = self.CountWaysUtil(mask,taskno+1)
47+
48+
# now assign the tasks one by one to all possible persons and recursively assign for the remaining tasks.
49+
if taskno in self.task:
50+
for p in self.task[taskno]:
51+
52+
# if p is already given a task
53+
if mask & (1<<p):
54+
continue
55+
56+
# assign this task to p and change the mask value. And recursively assign tasks with the new mask value.
57+
total_ways_util+=self.CountWaysUtil(mask|(1<<p),taskno+1)
58+
59+
# save the value.
60+
self.dp[mask][taskno] = total_ways_util
61+
62+
return self.dp[mask][taskno]
63+
64+
def countNoOfWays(self,task_performed):
65+
66+
# Store the list of persons for each task
67+
for i in range(len(task_performed)):
68+
for j in task_performed[i]:
69+
self.task[j].append(i)
70+
71+
# call the function to fill the DP table, final answer is stored in dp[0][1]
72+
return self.CountWaysUtil(0,1)
73+
74+
75+
if __name__ == '__main__':
76+
77+
total_tasks = 5 #total no of tasks (the value of N)
78+
79+
#the list of tasks that can be done by M persons.
80+
task_performed = [
81+
[ 1 , 3 , 4 ],
82+
[ 1 , 2 , 5 ],
83+
[ 3 , 4 ]
84+
]
85+
print(AssignmentUsingBitmask(task_performed,total_tasks).countNoOfWays(task_performed))
86+
"""
87+
For the particular example the tasks can be distributed as
88+
(1,2,3), (1,2,4), (1,5,3), (1,5,4), (3,1,4), (3,2,4), (3,5,4), (4,1,3), (4,2,3), (4,5,3)
89+
total 10
90+
"""

0 commit comments

Comments
 (0)