Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e147166

Browse files
committedAug 2, 2024·
Added doctests for AssignmentUsingBitmask class and fixed test cases
1 parent 240d1b7 commit e147166

File tree

1 file changed

+56
-29
lines changed

1 file changed

+56
-29
lines changed
 

‎dynamic_programming/bitmask.py

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,116 @@
11
"""
2-
32
This is a Python implementation for questions involving task assignments between people.
4-
Here Bitmasking and DP are used for solving this.
3+
Bitmasking and DP are used for solving this problem.
54
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.
5+
Question:
6+
We have N tasks and M people. Each person in M can do only certain of these tasks. Also,
7+
a person can do only one task, and a task is performed only by one person.
8+
Find the total number of ways in which the tasks can be distributed.
109
"""
1110

1211
from collections import defaultdict
1312

14-
1513
class AssignmentUsingBitmask:
1614
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
15+
"""
16+
Initialize the AssignmentUsingBitmask class.
17+
18+
:param task_performed: A list of lists where each sublist contains the tasks that a person can perform.
19+
:param total: Total number of tasks.
20+
21+
>>> a = AssignmentUsingBitmask([[1, 3, 4], [1, 2, 5], [3, 4]], 5)
22+
>>> a.total_tasks
23+
5
24+
>>> a.final_mask
25+
7
26+
"""
27+
self.total_tasks = total # total number of tasks (N)
28+
29+
# DP table will have a dimension of (2^M) x (N+1)
2030
# 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-
]
31+
self.dp = [[-1 for _ in range(total + 1)] for _ in range(2 ** len(task_performed))]
2432

2533
self.task = defaultdict(list) # stores the list of persons for each task
2634

27-
# final_mask is used to check if all persons are included by setting all bits
28-
# to 1
35+
# final_mask is used to check if all persons are included by setting all bits to 1
2936
self.final_mask = (1 << len(task_performed)) - 1
3037

3138
def count_ways_until(self, mask, task_no):
32-
# if mask == self.finalmask all persons are distributed tasks, return 1
39+
"""
40+
Count the number of ways to assign tasks given a current mask and task number.
41+
42+
:param mask: Current mask representing which persons have been assigned tasks.
43+
:param task_no: The current task number being considered.
44+
:return: The number of ways to assign tasks starting from the current state.
45+
46+
>>> a = AssignmentUsingBitmask([[1, 3, 4], [1, 2, 5], [3, 4]], 5)
47+
>>> a.count_ways_until(0, 1)
48+
0
49+
"""
50+
# If mask == self.final_mask, all persons are distributed tasks, return 1
3351
if mask == self.final_mask:
3452
return 1
3553

36-
# if not everyone gets the task and no more tasks are available, return 0
54+
# If no more tasks are available, return 0
3755
if task_no > self.total_tasks:
3856
return 0
3957

40-
# if case already considered
58+
# If case already considered
4159
if self.dp[mask][task_no] != -1:
4260
return self.dp[mask][task_no]
4361

44-
# Number of ways when we don't this task in the arrangement
62+
# Number of ways when we don't use this task in the arrangement
4563
total_ways_util = self.count_ways_until(mask, task_no + 1)
4664

47-
# now assign the tasks one by one to all possible persons and recursively
65+
# Now assign the tasks one by one to all possible persons and recursively
4866
# assign for the remaining tasks.
4967
if task_no in self.task:
5068
for p in self.task[task_no]:
51-
# if p is already given a task
69+
# If p is already given a task
5270
if mask & (1 << p):
5371
continue
5472

55-
# assign this task to p and change the mask value. And recursively
73+
# Assign this task to p and change the mask value. Recursively
5674
# assign tasks with the new mask value.
5775
total_ways_util += self.count_ways_until(mask | (1 << p), task_no + 1)
5876

59-
# save the value.
77+
# Save the value
6078
self.dp[mask][task_no] = total_ways_util
6179

6280
return self.dp[mask][task_no]
6381

6482
def count_no_of_ways(self, task_performed):
83+
"""
84+
Count the total number of ways to distribute tasks given the tasks each person can perform.
85+
86+
:param task_performed: A list of lists where each sublist contains the tasks that a person can perform.
87+
:return: The total number of ways to distribute tasks.
88+
89+
>>> a = AssignmentUsingBitmask([[1, 3, 4], [1, 2, 5], [3, 4]], 5)
90+
>>> a.count_no_of_ways([[1, 3, 4], [1, 2, 5], [3, 4]])
91+
10
92+
"""
6593
# Store the list of persons for each task
6694
for i in range(len(task_performed)):
6795
for j in task_performed[i]:
6896
self.task[j].append(i)
6997

70-
# call the function to fill the DP table, final answer is stored in dp[0][1]
98+
# Call the function to fill the DP table, final answer is stored in dp[0][1]
7199
return self.count_ways_until(0, 1)
72100

73-
74101
if __name__ == "__main__":
75-
total_tasks = 5 # total no of tasks (the value of N)
102+
total_tasks = 5 # Total number of tasks (the value of N)
76103

77-
# the list of tasks that can be done by M persons.
104+
# The list of tasks that can be done by M persons.
78105
task_performed = [[1, 3, 4], [1, 2, 5], [3, 4]]
79106
print(
80107
AssignmentUsingBitmask(task_performed, total_tasks).count_no_of_ways(
81108
task_performed
82109
)
83110
)
84111
"""
85-
For the particular example the tasks can be distributed as
112+
For the particular example, the tasks can be distributed as
86113
(1,2,3), (1,2,4), (1,5,3), (1,5,4), (3,1,4),
87114
(3,2,4), (3,5,4), (4,1,3), (4,2,3), (4,5,3)
88-
total 10
115+
Total: 10
89116
"""

0 commit comments

Comments
 (0)
Please sign in to comment.