class Solution:
def minNumberOfSemesters(
self,
n: int,
relations: list[list[int]],
k: int,
) -> int:
# dp[i] := the minimum number of semesters to take the courses, where i is
# the bitmask of the taken courses
dp = [n] * (1 << n)
# prereq[i] := bitmask of all dependencies of course i
prereq = [0] * n
for prevCourse, nextCourse in relations:
prereq[nextCourse - 1] |= 1 << prevCourse - 1
dp[0] = 0 # Don't need time to finish 0 course.
for i in range(1 << n):
# the bitmask of all the courses can be taken
coursesCanBeTaken = 0
# Can take the j-th course if i contains all of j's prerequisites.
for j in range(n):
if (i & prereq[j]) == prereq[j]:
coursesCanBeTaken |= 1 << j
# Don't take any course which is already taken.
# (i represents set of courses that are already taken)
coursesCanBeTaken &= ~i
# Enumerate every bitmask subset of `coursesCanBeTaken`.
s = coursesCanBeTaken
while s:
if s.bit_count() <= k:
# Any combination of courses (if <= k) can be taken now.
# i | s := combining courses taken with courses can be taken.
dp[i | s] = min(dp[i | s], dp[i] + 1)
s = (s - 1) & coursesCanBeTaken
return dp[-1]