🧠
Brute Force (Pure Recursion)
💡 Starting with brute force helps understand the problem's combinatorial nature and why naive recursion is inefficient due to repeated states.
Intuition
Try assigning each cap liked by the current person if it is not already assigned, then recurse for the next person until all are assigned.
Algorithm
- Start with the first person and an empty set of assigned caps.
- For the current person, try each cap they like that is not assigned yet.
- Assign the cap and recurse for the next person.
- If all persons are assigned, increment the count.
💡 The recursion tree grows exponentially because each person can try multiple caps, and the same states are recomputed multiple times.
Recurrence:ways(i, mask) = sum over caps c liked by person i and not in mask of ways(i+1, mask | (1 << c))
MOD = 10**9 + 7
def count_ways(person_caps, i=0, mask=0, memo=None):
if memo is None:
memo = {}
n = len(person_caps)
if i == n:
return 1
if (i, mask) in memo:
return memo[(i, mask)]
ways = 0
for cap in person_caps[i]:
if not (mask & (1 << (cap - 1))):
ways += count_ways(person_caps, i + 1, mask | (1 << (cap - 1)), memo)
ways %= MOD
memo[(i, mask)] = ways
return ways
# Example usage:
if __name__ == '__main__':
person_caps = [[5, 100], [1, 5, 100], [1, 2]]
print(count_ways(person_caps))
Line Notes
if memo is None:Initialize memo dictionary only once to store computed states
if i == n:Base case: all persons assigned, count as one valid way
if (i, mask) in memo:Return cached result to avoid recomputation
if not (mask & (1 << (cap - 1)))Check if cap is not assigned yet using bitmask
import java.util.*;
public class CountWaysAssignCap {
static final int MOD = 1000000007;
static Map<String, Integer> memo = new HashMap<>();
public static int countWays(List<List<Integer>> personCaps, int i, int mask) {
if (i == personCaps.size()) return 1;
String key = i + "," + mask;
if (memo.containsKey(key)) return memo.get(key);
int ways = 0;
for (int cap : personCaps.get(i)) {
if ((mask & (1 << (cap - 1))) == 0) {
ways += countWays(personCaps, i + 1, mask | (1 << (cap - 1)));
ways %= MOD;
}
}
memo.put(key, ways);
return ways;
}
public static void main(String[] args) {
List<List<Integer>> personCaps = new ArrayList<>();
personCaps.add(Arrays.asList(5, 100));
personCaps.add(Arrays.asList(1, 5, 100));
personCaps.add(Arrays.asList(1, 2));
System.out.println(countWays(personCaps, 0, 0));
}
}
Line Notes
static Map<String, Integer> memo = new HashMap<>();Memoize results for states to avoid recomputation
if (i == personCaps.size()) return 1;Base case: all persons assigned successfully
if ((mask & (1 << (cap - 1))) == 0)Check if cap is free using bitmask
memo.put(key, ways);Store computed ways for current state
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
int n;
vector<vector<int>> personCaps;
unordered_map<long long, int> memo;
int countWays(int i, int mask) {
if (i == n) return 1;
long long key = ((long long)i << 32) | mask;
if (memo.count(key)) return memo[key];
int ways = 0;
for (int cap : personCaps[i]) {
if ((mask & (1 << (cap - 1))) == 0) {
ways += countWays(i + 1, mask | (1 << (cap - 1)));
ways %= MOD;
}
}
return memo[key] = ways;
}
int main() {
personCaps = {{5, 100}, {1, 5, 100}, {1, 2}};
n = (int)personCaps.size();
cout << countWays(0, 0) << "\n";
return 0;
}
Line Notes
long long key = ((long long)i << 32) | mask;Combine i and mask into a single key for memoization
if (i == n) return 1;Base case: all persons assigned
if ((mask & (1 << (cap - 1))) == 0)Check if cap is available
return memo[key] = ways;Store and return computed ways for current state
const MOD = 1e9 + 7;
function countWays(personCaps, i = 0, mask = 0, memo = new Map()) {
if (i === personCaps.length) return 1;
const key = i + ',' + mask;
if (memo.has(key)) return memo.get(key);
let ways = 0;
for (const cap of personCaps[i]) {
if ((mask & (1 << (cap - 1))) === 0) {
ways += countWays(personCaps, i + 1, mask | (1 << (cap - 1)), memo);
ways %= MOD;
}
}
memo.set(key, ways);
return ways;
}
// Example usage:
const personCaps = [[5, 100], [1, 5, 100], [1, 2]];
console.log(countWays(personCaps));
Line Notes
if (i === personCaps.length) return 1;Base case: all persons assigned caps
const key = i + ',' + mask;Create unique key for memoization
if ((mask & (1 << (cap - 1))) === 0)Check if cap is free using bitmask
memo.set(key, ways);Cache computed result for current state
TimeO(n * 2^m * k) where n is persons, m is caps, k average caps per person
SpaceO(n * 2^m) for memoization
Each state is defined by person index and assigned caps bitmask; recursion explores all subsets
💡 For n=10 and caps=100, this is huge and impractical, but good to understand problem structure
Interview Verdict: TLE / Use only to introduce problem and motivate DP
This approach is too slow for large inputs but essential to understand before optimizing