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