VOOZH about

URL: https://www.geeksforgeeks.org/dsa/bitmasking-and-dynamic-programming-set-1-count-ways-to-assign-unique-cap-to-every-person/

⇱ Count Ways To Assign Unique Cap To Every Person - GeeksforGeeks


  • Courses
  • Tutorials
  • Interview Prep

Count Ways To Assign Unique Cap To Every Person

Last Updated : 23 Jul, 2025

Given n people and 100 types of caps labelled from 1 to 100, along with a 2D integer array caps where caps[i] represents the list of caps preferred by the i-th person, the task is to determine the number of ways the n people can wear different caps.

Example:

Input: caps = [[3, 4], [4, 5], [5]]
Output: 1
Explanation: First person choose cap 3, Second person choose cap 4 and last one cap 5.

Input: caps = [[3, 5, 1], [3, 5]]
Output: 4
Explanation: There are 4 ways to choose hats: (3, 5), (5, 3), (1, 3) and (1, 5)

Using Recursion

In the recursive approach, there are two cases for each cap:

  1. Skip the current cap, this means we move to the next cap without assigning the current cap to any person, keeping the assigned count unchanged. The recursive call will look like: dfs(assignedCount, cap+1)
  2. Assign the current cap to each person who prefers it: For each person who likes the current cap, if they do not already have a cap assigned, we assign this cap to them and move to the next cap with the assigned count incremented by 1. After the recursive call, we backtrack by unassigning the cap to explore other possibilities.

The recurrence relation is as follows:

Base Cases:

  1. If assignedCount == totalPeople, return 1, as this indicates all people have a unique cap assigned.
  2. If cap > 100, return 0, as this means there are no more caps left to assign but not all people have received a cap.
  • dfs(assignedCount, cap) = dfs(assignedCount, cap+1) + ∑person in capToPeople[cap] dfs(assignedCount+1, cap+1) if assignedPeople[person] == false , we loop through each person who prefers the current cap, check if they have already been assigned a cap, and if not, assign it to them and recurse to explore further assignments with the updated assignedCount.

Output
8

The above solution will have a exponential time complexity.

Using Top-Down DP (Memoization) - O(n * 2^nTime and O(2^n) Space

If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming.

1. Optimal Substructure: The problem exhibits optimal substructure, meaning that the solution to the problem can be derived from the solutions of smaller subproblems.

The recursive relation is:

  • ways = dfs(allMask, assignedPeople, cap+1) (skip current cap)
  • ways = ways + dfs(allMask, assignedPeople ∣ (1 << person), cap+1) (assign current cap to a person)

2. Overlapping Subproblems:

Many subproblems are computed multiple times with the same parameters (cap, assignedPeople). To avoid recomputing the same subproblems, we store the result in a memoization table memo[cap][assignedPeople], which stores the number of ways to assign caps for a given cap and assignedPeople combination.


Output
8

Using Bottom-Up DP (Tabulation) – O(n * 2^nTime and O(2^n) Space

We use a 2D DP table of size (number of caps + 1) * (2^n). The state dp[cap][assignedPeople] represents the number of ways to assign caps to people considering the first cap caps and assigning caps to the people represented by the bitmask assignedPeople.

Dynamic Programming Relation:

Base Case: dp[0][0] = 1, If no caps are assigned and no people are assigned any caps, there is 1 way to do nothing.

Skip the current cap:

  • dp[cap][assignedPeople] += dp[cap-1][assignedPeople]

Assign the current cap to a person who hasn't been assigned a cap:

  • dp[cap][assignedPeople | (1 << person)] += dp[cap - 1][assignedPeople]

After filling the DP table, the final result will be stored in dp[100][allMask], which represents the number of ways to assign all caps to all people.


Output
8
Comment
Article Tags: