<p>You are given an integer <code>n</code>, which indicates that there are <code>n</code> courses labeled from <code>1</code> to <code>n</code>. You are also given an array <code>relations</code> where <code>relations[i] = [prevCourse<sub>i</sub>, nextCourse<sub>i</sub>]</code>, representing a prerequisite relationship between course <code>prevCourse<sub>i</sub></code> and course <code>nextCourse<sub>i</sub></code>: course <code>prevCourse<sub>i</sub></code> has to be taken before course <code>nextCourse<sub>i</sub></code>. Also, you are given the integer <code>k</code>.</p>

<p>In one semester, you can take <strong>at most</strong> <code>k</code> courses as long as you have taken all the prerequisites in the <strong>previous</strong> semesters for the courses you are taking.</p>

<p>Return <em>the <strong>minimum</strong> number of semesters needed to take all courses</em>. The testcases will be generated such that it is possible to take every course.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2020/05/22/leetcode_parallel_courses_1.png" style="width: 269px; height: 147px;" />
<pre>
<strong>Input:</strong> n = 4, relations = [[2,1],[3,1],[1,4]], k = 2
<strong>Output:</strong> 3
<strong>Explanation:</strong> The figure above represents the given graph.
In the first semester, you can take courses 2 and 3.
In the second semester, you can take course 1.
In the third semester, you can take course 4.
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2020/05/22/leetcode_parallel_courses_2.png" style="width: 271px; height: 211px;" />
<pre>
<strong>Input:</strong> n = 5, relations = [[2,1],[3,1],[4,1],[1,5]], k = 2
<strong>Output:</strong> 4
<strong>Explanation:</strong> The figure above represents the given graph.
In the first semester, you can only take courses 2 and 3 since you cannot take more than two per semester.
In the second semester, you can take course 4.
In the third semester, you can take course 1.
In the fourth semester, you can take course 5.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= n &lt;= 15</code></li>
	<li><code>1 &lt;= k &lt;= n</code></li>
	<li><code>0 &lt;= relations.length &lt;= n * (n-1) / 2</code></li>
	<li><code>relations[i].length == 2</code></li>
	<li><code>1 &lt;= prevCourse<sub>i</sub>, nextCourse<sub>i</sub> &lt;= n</code></li>
	<li><code>prevCourse<sub>i</sub> != nextCourse<sub>i</sub></code></li>
	<li>All the pairs <code>[prevCourse<sub>i</sub>, nextCourse<sub>i</sub>]</code> are <strong>unique</strong>.</li>
	<li>The given graph is a directed acyclic graph.</li>
</ul>

from collections import deque

class Solution:
    def minNumberOfSemesters(self, n: int, relations: List[List[int]], k: int) -> int:


        # Step 1: Build prerequisite bitmasks
        prereq = [0] * n
        for u, v in relations:
            prereq[v - 1] |= (1 << (u - 1))
        
        # Step 2: BFS Initialization
        queue = deque([(0, 0)])  # (current mask, number of semesters)
        visited = set([0])  # We start with no courses taken
        
        # Step 3: BFS traversal over bitmask states
        while queue:
            mask, semesters = queue.popleft()
            
            # If all courses are taken, return the number of semesters
            if mask == (1 << n) - 1:
                return semesters
            
            # Step 4: Find all available courses (those with prerequisites satisfied)
            available_mask = 0
            for course in range(n):
                if (mask & prereq[course]) == prereq[course] and not (mask & (1 << course)):
                    available_mask |= (1 << course)
            
            # Step 5: Iterate through all subsets of available courses
            subset = available_mask
            while subset:
                if bin(subset).count('1') <= k:  # Take only subsets of size <= k
                    new_mask = mask | subset
                    if new_mask not in visited:
                        visited.add(new_mask)
                        queue.append((new_mask, semesters + 1))
                # Move to the next subset
                subset = (subset - 1) & available_mask
        
        return -1  # If no solution is found (though it's guaranteed one exists)
21600