Cho n khóa học (1..n), mảng relations với relations[i] = (prev, next) (prev phải học trước next). Mỗi học kỳ học tối đa k khóa, miễn là đã học đủ điều kiện tiên quyết. Tìm số học kỳ tối thiểu.
Ví dụ: n=6, relations=[(1,3),(2,5),(2,4),(5,6)], k=2 → 3 học kỳ. Kỳ 1: học 1,2; Kỳ 2: học 5 và 3 (hoặc 4); Kỳ 3: học phần còn lại.
Giải thuật (Topological sort + heuristic)
- Xây đồ thị:
g1[i]= danh sách tiên quyết củai,g2[i]= danh sách khóa phụ thuộc vàoi. - Tính
weight[i] = len(g1[i])(số tiên quyết). - Lan truyền trọng số:
w[x] = max(w[x], weight[i])choxtrongg1[i]. - Lặp cho đến khi học đủ
nkhóa:- Thu thập khóa sẵn sàng (
g1[i]rỗng, chưa học). - Nếu >
kkhóa: sắp xếp giảm dần theow[i], lấykkhóa đầu. - Cập nhật đồ thị: xóa khóa đã học khỏi
g1của các khóa phụ thuộc. - Tăng số học kỳ.
- Thu thập khóa sẵn sàng (
Ví dụ minh họa
def solve(n, relations, k):
taken = set()
g1 = [[] for _ in range(n)]
g2 = [[] for _ in range(n)]
w = [0] * n
semester = 0
for x in relations:
g1[x[1]-1].append(x[0]-1)
g2[x[0]-1].append(x[1]-1)
weight = list(map(len, g1))
for i in range(n):
for x in g1[i]:
w[x] = max(w[x], weight[i])
while len(taken) < n:
courses = []
for i in range(n):
if not g1[i] and i not in taken:
courses.append([i, w[i]])
if len(courses) > k:
courses = sorted(courses, key=lambda x: x[1], reverse=True)
courses = courses[:k]
semester += 1
for x in courses:
for y in g2[x[0]]:
g1[y].remove(x[0])
g2[x[0]] = []
taken.add(x[0])
return semester
n = 6
relations = [(1,3),(2,5),(2,4),(5,6)]
k = 2
print(solve(n, relations, k))
Đầu vào
6, [(1,3),(2,5),(2,4),(5,6)], 2
Đầu ra
3