Skip to content

Commit f31e2a1

Browse files
committed
Pushing bitmask implementation to the repo - added more examples for testing
1 parent eb78909 commit f31e2a1

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

DynamicProgramming/BitMask.py

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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
8+
a person can do only one task and a task is performed only by one person.
9+
Find the total no of ways in which the tasks can be distributed.
10+
"""
11+
12+
from collections import defaultdict
13+
14+
15+
class AssignmentUsingBitmask:
16+
def __init__(self, task_performed, total):
17+
self.total_tasks = total # total no of tasks (N)
18+
19+
# DP table will have a dimension of (2^M)*N
20+
# initially all values are set to -1
21+
self.dp = [
22+
[-1 for i in range(total + 1)] for j in range(2 ** len(task_performed))
23+
]
24+
25+
self.task = defaultdict(list) # stores the list of persons for each task
26+
27+
# final_mask is used to check if all persons are included by setting all bits
28+
# to 1
29+
self.final_mask = (1 << len(task_performed)) - 1
30+
31+
def count_ways_until(self, mask, task_no):
32+
# if mask == self.finalmask all persons are distributed tasks, return 1
33+
if mask == self.final_mask:
34+
return 1
35+
36+
# if not everyone gets the task and no more tasks are available, return 0
37+
if task_no > self.total_tasks:
38+
return 0
39+
40+
# if case already considered
41+
if self.dp[mask][task_no] != -1:
42+
return self.dp[mask][task_no]
43+
44+
# Number of ways when we don't this task in the arrangement
45+
total_ways_util = self.count_ways_until(mask, task_no + 1)
46+
47+
# now assign the tasks one by one to all possible persons and recursively
48+
# assign for the remaining tasks.
49+
if task_no in self.task:
50+
for p in self.task[task_no]:
51+
# if p is already given a task
52+
if mask & (1 << p):
53+
continue
54+
55+
# assign this task to p and change the mask value. And recursively
56+
# assign tasks with the new mask value.
57+
total_ways_util += self.count_ways_until(mask | (1 << p), task_no + 1)
58+
59+
# save the value.
60+
self.dp[mask][task_no] = total_ways_util
61+
62+
return self.dp[mask][task_no]
63+
64+
def count_no_of_ways(self, task_performed):
65+
# Store the list of persons for each task
66+
for i in range(len(task_performed)):
67+
for j in task_performed[i]:
68+
self.task[j].append(i)
69+
70+
# call the function to fill the DP table, final answer is stored in dp[0][1]
71+
return self.count_ways_until(0, 1)
72+
73+
74+
if __name__ == "__main__":
75+
total_tasks = 5 # total no of tasks (the value of N)
76+
77+
# Example 1
78+
task_performed = [[1, 3, 4], [1, 2, 5], [3, 4]]
79+
print(
80+
AssignmentUsingBitmask(task_performed, total_tasks).count_no_of_ways(
81+
task_performed
82+
)
83+
)
84+
85+
# Example 2
86+
task_performed = [[1, 2], [2, 3], [1, 3]]
87+
print(
88+
AssignmentUsingBitmask(task_performed, total_tasks).count_no_of_ways(
89+
task_performed
90+
)
91+
)
92+
93+
# Example 3
94+
task_performed = [[1, 2, 3], [2, 3, 4], [1, 4, 5]]
95+
print(
96+
AssignmentUsingBitmask(task_performed, total_tasks).count_no_of_ways(
97+
task_performed
98+
)
99+
)
100+
101+
# Example 4
102+
task_performed = [[1], [2], [3], [4], [5]]
103+
print(
104+
AssignmentUsingBitmask(task_performed, total_tasks).count_no_of_ways(
105+
task_performed
106+
)
107+
)
108+
109+
# Example 5
110+
task_performed = [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
111+
print(
112+
AssignmentUsingBitmask(task_performed, total_tasks).count_no_of_ways(
113+
task_performed
114+
)
115+
)
116+
117+
# the list of tasks that can be done by M persons.
118+
task_performed = [[1, 3, 4], [1, 2, 5], [3, 4]]
119+
print(
120+
AssignmentUsingBitmask(task_performed, total_tasks).count_no_of_ways(
121+
task_performed
122+
)
123+
)

0 commit comments

Comments
 (0)