OR-Tools Day11

개발공부를해보자·2025년 6월 17일

실습 코드

# ------------------ Day11(25.06.17) ------------------

from ortools.sat.python import cp_model
import random

# 데이터 생성
classes = [f'{grade}{section}' for grade in range(1, 6) for section in ['A', 'B']]
teachers = [f'T{i}' for i in range(1, 8)]
subjects = ['Math', 'English', 'Science', 'History', 'Art']
rooms = [f'R{i}' for i in range(1, 50)]
time_slots = [f'{day}-{period}' for day in range(1, 6) for period in range(1, 7)]

# 교사-과목 매칭(랜덤)
teacher_subjects = {t: random.sample(subjects, k=5) for t in teachers}

# 반별 과목별 수업시수(랜덤 예시)
class_subject_requirements = {
    c: {s: random.randint(3, 5) for s in subjects} for c in classes
}

model = cp_model.CpModel()
x = {}

# 변수 선언(불가능한 조합 제외)
for c in classes:
    for t in time_slots:
        for s in subjects:
            for teacher in teachers:
                if s in teacher_subjects[teacher]:
                    for room in rooms:
                        x[c, t, s, teacher, room] = model.NewBoolVar(f'x_{c}_{t}_{s}_{teacher}_{room}')

# 기본 제약조건
for c in classes:
    for t in time_slots:
        model.Add(
            sum(x[c, t, s, teacher, room]
                for s in subjects
                for teacher in teachers if s in teacher_subjects[teacher]
                for room in rooms
                ) <= 1
        )

for c in classes:
    for s in subjects:
        model.Add(
            sum(x[c, t, s, teacher, room]
                for t in time_slots
                for teacher in teachers if s in teacher_subjects[teacher]
                for room in rooms
                ) == class_subject_requirements[c][s]
        )

for t in time_slots:
    for teacher in teachers:
        model.Add(
            sum(x[c, t, s, teacher, room]
                for c in classes
                for s in subjects if s in teacher_subjects[teacher]
                for room in rooms
                ) <= 1
        )

for t in time_slots:
    for room in rooms:
        model.Add(
            sum(x[c, t, s, teacher, room]
                for c in classes
                for s in subjects
                for teacher in teachers if s in teacher_subjects[teacher]
                ) <= 1
        )

# 시간 제한 옵션
solver = cp_model.CpSolver()
solver.parameters.max_time_in_seconds = 60
status = solver.Solve(model)

if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
    print('해를 찾았습니다! (일부만 출력)')
    for c in classes[:2]:  # 일부 반만 출력
        print(f'\n{c} 시간표:')
        for t in time_slots[:6]:  # 일부 시간만 출력
            for s in subjects:
                for teacher in teachers:
                    if s in teacher_subjects[teacher]:
                        for room in rooms:
                            if solver.Value(x[c, t, s, teacher, room]):
                                print(f'  {t}: {s} ({teacher}, {room})')
else:
    print('해를 찾지 못했습니다. (시간 초과 또는 infeasible)')

'''
해를 찾았습니다! (일부만 출력)

1A 시간표:
  1-2: Science (T7, R5)
  1-5: Math (T7, R13)

1B 시간표:
  1-1: English (T1, R30)
  1-3: Math (T2, R12)
'''


# 해를 찾지 못했을 경우 어떤 조건이 빡빡한지 확인
print("\n[반별 수업시수 체크]")
for c in classes:
    total_required = sum(class_subject_requirements[c].values())
    print(f"{c}: 필요 수업 {total_required}, 가능한 시간 {len(time_slots)}")
    if total_required > len(time_slots):
        print(f"⚠️ {c}의 수업 요구가 시간보다 많음!")

print("\n[과목별 교사 수 체크]")
for s in subjects:
    teachers_for_s = [t for t in teachers if s in teacher_subjects[t]]
    print(f"{s}: 담당 교사 {teachers_for_s}")
    if len(teachers_for_s) == 0:
        print(f"⚠️ {s}를 가르칠 교사가 없음!")

print("\n[시간별 교실 수 체크]")
max_parallel_classes = max(sum(class_subject_requirements[c][s] for s in subjects) for c in classes)
print(f"가장 많은 수업이 필요한 반의 총 수업: {max_parallel_classes}, 교실 수: {len(rooms)}")


for s in subjects:
    total_required = sum(class_subject_requirements[c][s] for c in classes)
    total_teacher_capacity = len([t for t in teachers if s in teacher_subjects[t]]) * len(time_slots)
    print(f"{s}: 총 요구 {total_required}, 담당 교사 총 가능 {total_teacher_capacity}")
    if total_required > total_teacher_capacity:
        print(f"⚠️ {s} 과목의 수업 요구가 교사 담당 가능 시간보다 많음!")


for t in teachers:
    teacher_load = 0
    for s in teacher_subjects[t]:
        teacher_load += sum(class_subject_requirements[c][s] for c in classes)
    print(f"{t}: 담당해야 할 수업 {teacher_load}, 최대 가능 {len(time_slots)}")
    if teacher_load > len(time_slots):
        print(f"⚠️ {t}의 담당 수업이 너무 많음!")

for s in subjects:
    teachers_for_s = [t for t in teachers if s in teacher_subjects[t]]
    print(f"{s}: 담당 교사 {teachers_for_s}")
    if len(teachers_for_s) == 0:
        print(f"⚠️ {s}를 가르칠 교사가 없음!")
profile
개발 공부하는 30대 비전공자 직장인

0개의 댓글