Lập thời khóa biểu

Từ quy định đào tạo đến ràng buộc kiểm chứng được

Đặc tả ràng buộc đi lại giữa hai cơ sở, chọn đơn vị phạt và xây các ca kiểm thử tại ranh giới.

Vấn đề nghiên cứuTrung cấp16 phút đọcPython

Thích và đánh giá Bình luận và hỏi đáp
Hai ca ở hai cơ sở. Khoảng trống 20 phút vừa đủ để đáp ứng thời gian di chuyển tối thiểu 20 phút.
Hai ca ở hai cơ sở. Khoảng trống 20 phút vừa đủ để đáp ứng thời gian di chuyển tối thiểu 20 phút. Mở hình lớn ↗

1. Làm rõ phát biểu nghiệp vụ trước khi viết ràng buộc

Phát biểu “tránh xếp giảng viên dạy liên tiếp ở hai cơ sở” chứa nhiều cách hiểu. Đơn vị đào tạo có thể cấm hai ca quá sát vì giảng viên không kịp di chuyển. Khi có đủ thời gian, đơn vị vẫn muốn giảm số lần chuyển cơ sở trong ngày. Tách hai ý này giúp phân biệt điều kiện khả thi với mục tiêu cải thiện lịch.

Ví dụ dưới đây dùng hai cơ sở A và B. Thời gian di chuyển giả định là 20 phút theo chiều A→B và 25 phút theo chiều B→A. Đây là số liệu minh họa cho phương pháp đặc tả. Khi áp dụng thực tế, cần thống nhất nguồn số liệu, khung giờ và quy tắc xử lý các trường hợp đặc biệt.

2. Tạo bảng đặc tả với phạm vi và đơn vị tính

Mã minh họaLoạiĐiều kiệnĐơn vị kiểm tra
H01CứngHai ca của cùng một giảng viên không chồng thời gian.Ca dạy trong ngày
H02CứngHai ca liên tiếp ở hai cơ sở có khoảng trống đủ cho hướng di chuyển.Cặp ca liên tiếp
S01MềmPhạt 3 điểm cho mỗi lượt đổi cơ sở trên lịch khả thi.Lượt đổi giữa hai ca liên tiếp

Biểu diễn mỗi ca bằng khoảng [bắt đầu, kết thúc). Hai ca cùng cơ sở có thể nối nhau ngay khi ca trước kết thúc. Khoảng trống giữa hai ca bằng giờ bắt đầu của ca sau trừ giờ kết thúc của ca trước. Với lịch A–B–A, số lượt chuyển bằng 2. Tính trên mọi cặp lớp khác cơ sở sẽ đếm cả các cặp không liên tiếp và làm thay đổi ý nghĩa điểm phạt.

3. Viết bộ kiểm tra nhỏ cho một giảng viên, một ngày

Mã kiểm tra định dạng dữ liệu, sắp thứ tự các ca và xét từng cặp kề nhau. Để quyết định có chồng thời gian hay không, tìm ít nhất một cặp kề chồng nhau là đủ. Nếu cần liệt kê mọi cặp xung đột để giải thích, hãy mở rộng bước dò lỗi. Mã trả điểm mềm khi lịch đã thỏa mọi ràng buộc cứng của ví dụ.

Môi trường thực hành. Python 3.10 trở lên. Ví dụ dùng thư viện chuẩn Python.

Python · dac_ta_rang_buoc.pyTải mã nguồn
"""Kiểm tra lịch trong một ngày của một giảng viên.

Thời gian tính bằng phút kể từ 00:00. Khoảng dạy là [bat_dau, ket_thuc).
"""
from dataclasses import dataclass


@dataclass(frozen=True)
class CaDay:
    ma: str
    bat_dau: int
    ket_thuc: int
    co_so: str


DI_CHUYEN = {("A", "B"): 20, ("B", "A"): 25}


def danh_gia(cac_ca):
    loi = []
    luot_chuyen = 0
    lich = sorted(cac_ca, key=lambda ca: (ca.bat_dau, ca.ket_thuc, ca.ma))
    for ca in lich:
        if not 0 <= ca.bat_dau < ca.ket_thuc <= 1440 or ca.co_so not in {"A", "B"}:
            raise ValueError(f"Dữ liệu đầu vào không hợp lệ: {ca.ma}")

    for truoc, sau in zip(lich, lich[1:]):
        khoang_trong = sau.bat_dau - truoc.ket_thuc
        if khoang_trong < 0:
            loi.append(f"H01 {truoc.ma}/{sau.ma}: ca dạy chồng nhau")
            continue

        if truoc.co_so != sau.co_so:
            toi_thieu = DI_CHUYEN[truoc.co_so, sau.co_so]
            luot_chuyen += 1
            if khoang_trong < toi_thieu:
                loi.append(f"H02 {truoc.ma}/{sau.ma}: thiếu {toi_thieu - khoang_trong} phút")

    # S01 tính theo lượt chuyển cơ sở giữa hai ca dạy liên tiếp.
    return loi, None if loi else 3 * luot_chuyen


if __name__ == "__main__":
    tiet_1 = CaDay("CTDL", 480, 540, "A")
    for gap in (19, 20, 21):
        tiet_2 = CaDay("KTPM", 540 + gap, 600 + gap, "B")
        print(gap, "phút:", danh_gia([tiet_1, tiet_2]))

    assert danh_gia([tiet_1, CaDay("KTPM", 560, 620, "B")]) == ([], 3)
    assert danh_gia([tiet_1, CaDay("KTPM", 540, 600, "A")]) == ([], 0)
    assert danh_gia([tiet_1, CaDay("KTPM", 539, 600, "A")])[1] is None
    assert danh_gia([tiet_1, CaDay("KTPM", 559, 620, "B")])[1] is None
    assert danh_gia([CaDay("KTPM", 480, 540, "B"), CaDay("CTDL", 560, 620, "A")])[1] is None

Chạy python dac_ta_rang_buoc.py. Với cặp A→B, khoảng trống 19 phút bị từ chối, còn 20 và 21 phút đều khả thi với 3 điểm phạt. Cặp B→A cách 20 phút vẫn không hợp lệ. Kiểm tra cả hai chiều để phát hiện lỗi vô tình dùng chung một giá trị di chuyển.

4. Các câu hỏi cần trả lời bằng dữ liệu thực tế

  • Đo thời gian thế nào? Khảo sát nhiều khung giờ để biết dùng một hằng số có đủ an toàn và thực tế không. Có thể so sánh chính sách dùng thời gian trung vị với một mức thận trọng hơn rồi đo ảnh hưởng lên số lịch khả thi.
  • Đánh đổi ra sao? So sánh số lượt chuyển cơ sở với mức sử dụng phòng và các ưu tiên giảng viên. Báo cáo từng thành phần điểm riêng để thấy tác động khi tăng trọng số S01.
  • Xử lý ngoại lệ ở đâu? Xác định cách mô hình hóa ca trực tuyến, ca được miễn di chuyển hoặc ngày có lịch đặc biệt. Mỗi ngoại lệ cần ít nhất một ví dụ hợp lệ và một phản ví dụ.

Định dạng ITC 2019 là điểm tham chiếu để đối chiếu kiểu dữ liệu và quy tắc di chuyển. Trước khi chuyển dữ liệu, hãy ghi rõ trường nào ánh xạ trực tiếp và trường nào cần mở rộng cho bối cảnh của cơ sở đào tạo.