문제
- 'A' 회사는 직원(people)이 7명이다.
- 직원들은 월요일(monday)과 공휴일(holiday)에 당직을 서야 한다.
- 2022년 당직을 서는 횟수를 최대한 공평하게 분배하라.
- 월요일 횟수와 공휴일 횟수를 따로 카운트한다. (월요일 당직과 공휴일 당직은 엄연히 다르다.)
- 월요일, 공휴일 관계없이 연속해서 당직을 서는 일이 없도록 한다. (즉, 지난 당직일에 당번이 나였는데 이번 당직일에 당번이 나면 안된다.)
import holidays
from datetime import date, timedelta
people = ['김', '나', '박', '이', '채', '신', '하']
monday_list = []
first_day = date(2022, 1, 1)
monday = first_day + timedelta(days= 7-first_day.weekday())
while monday.year == year:
monday_list.append(monday)
monday += timedelta(days= 7)
holiday_dict = holidays.KR(years=2022)
holiday_list = [holiday for holiday in holiday_dict.keys()]
풀이
import random
# 먼저, 공휴일인 월요일을 월요일 리스트에서 삭제합니다.
for holiday in holiday_list:
if holiday in monday_list:
monday_list.remove(holiday)
# 당직일 전체 리스트를 만듭니다.
sum_list = monday_list + holiday_list
sum_list.sort()
# 직원리스트를 셔플한 후, 직원별 스코어보드를 만듭니다. {person: [cnt_monday, cnt_holiday]}
random.shuffle(people)
person_dict = {}
for person in people:
person_dict[person] = [0, 0]
# 조건에 맞게 당직을 배정합니다.
prev = None
max_cnt_mon = 0
max_cnt_hol = 0
idx = 0
num = len(members)
for day in sum_list:
loop = 0
while True:
idx %= num
person= people[idx]
cnt = person_dict[person]
if loop < num:
idx += 1
if day in monday_list and cnt[0] <= max_cnt_mon:
charge_dict[day] = person
cnt[0] += 1
break
elif day in holiday_list and cnt[1] <= max_cnt_hol:
charge_dict[day] = person
cnt[1] += 1
break
else:
if day in monday_list:
max_cnt_mon += 1
elif day in holiday_list:
max_cnt_hol += 1
loop = 0
loop += 1
# 결과를 확인합니다.
print(person_dict)
print(charge_dict)
{'김': [7, 3],
'나': [6, 3],
'채': [6, 3],
'신': [7, 2],
'이': [7, 2],
'박': [7, 2],
'하': [6, 3]}
{datetime.date(2022, 1, 1): '김',
datetime.date(2022, 1, 3): '나',
datetime.date(2022, 1, 10): '채',
datetime.date(2022, 1, 17): '신',
datetime.date(2022, 1, 24): '이',
datetime.date(2022, 1, 31): '박',
datetime.date(2022, 2, 1): '하',
datetime.date(2022, 2, 2): '나',
datetime.date(2022, 2, 7): '박',
datetime.date(2022, 2, 14): '하',
datetime.date(2022, 2, 21): '김',
datetime.date(2022, 2, 28): '나',
datetime.date(2022, 3, 1): '채',
datetime.date(2022, 3, 7): '신',
datetime.date(2022, 3, 14): '이',
datetime.date(2022, 3, 21): '박',
datetime.date(2022, 3, 28): '하',
datetime.date(2022, 4, 4): '김',
datetime.date(2022, 4, 11): '채',
datetime.date(2022, 4, 18): '신',
datetime.date(2022, 4, 25): '이',
datetime.date(2022, 5, 1): '신',
datetime.date(2022, 5, 2): '박',
datetime.date(2022, 5, 5): '이',
datetime.date(2022, 5, 8): '박',
datetime.date(2022, 5, 9): '하',
datetime.date(2022, 5, 16): '김',
datetime.date(2022, 5, 23): '나',
datetime.date(2022, 5, 30): '채',
datetime.date(2022, 6, 6): '신',
datetime.date(2022, 6, 13): '이',
datetime.date(2022, 6, 20): '박',
datetime.date(2022, 6, 27): '하',
datetime.date(2022, 7, 4): '김',
datetime.date(2022, 7, 11): '나',
datetime.date(2022, 7, 18): '채',
datetime.date(2022, 7, 25): '신',
datetime.date(2022, 8, 1): '이',
datetime.date(2022, 8, 8): '박',
datetime.date(2022, 8, 15): '하',
datetime.date(2022, 8, 22): '김',
datetime.date(2022, 8, 29): '나',
datetime.date(2022, 9, 5): '채',
datetime.date(2022, 9, 9): '이',
datetime.date(2022, 9, 10): '김',
datetime.date(2022, 9, 11): '나',
datetime.date(2022, 9, 12): '채',
datetime.date(2022, 9, 19): '신',
datetime.date(2022, 9, 26): '하',
datetime.date(2022, 10, 3): '김',
datetime.date(2022, 10, 9): '나',
datetime.date(2022, 10, 10): '채',
datetime.date(2022, 10, 17): '신',
datetime.date(2022, 10, 24): '이',
datetime.date(2022, 10, 31): '박',
datetime.date(2022, 11, 7): '하',
datetime.date(2022, 11, 14): '김',
datetime.date(2022, 11, 21): '나',
datetime.date(2022, 11, 28): '채',
datetime.date(2022, 12, 5): '신',
datetime.date(2022, 12, 12): '이',
datetime.date(2022, 12, 19): '박',
datetime.date(2022, 12, 25): '하',
datetime.date(2022, 12, 26): '김'}
해설
for 문으로 당직일 리스트를 순회하며, while문 내에서 당직자를 배정하는 알고리즘입니다.
loop는 직원명단을 한바퀴 순회함을 체크하기 위해서 만들었습니다. 만약 한바퀴 순회할 때까지 당직자를 배정하지 못한다면 max_cnt(월요일 또는 공휴일)에 +1한 후 loop를 다시 0으로 만들어 다시 한바퀴 순회하며 배정할 수 있도록 했습니다.
idx는 직원명단에서 직원을 선택하는 인덱스로 사용하는데 나머지 연산(idx %= num)을 이용하여 0에서 마지막 번호(7명이면, 6)까지 차례로 반복하도록 했습니다.
person = people[idx]로 당직자 후보를 뽑은 후 이 후보가 (월요일, 공휴일 중 각 해당일의) max_cnt보다 낮은 score를 가지고 있다면 해당일의 당직자로 배정하고 idx에 +1하여 다음 당직일의 후보자 순회는 다음 idx의 사람부터 while문을 쓰도록 합니다. (코드의 중복을 피하기 위해서 idx += 1부터 시행했습니다. (shuffle된 직원 리스트라서 관계없다고 생각합니다.)
728x90
'개발' 카테고리의 다른 글
pyinstaller로 exe format 실행파일 만들기 (1) | 2022.08.17 |
---|---|
Raspi 4B 모니터 없이 셋업 중 VNC Viewer 'Cannot currently show the dekstop' (1) | 2022.05.30 |
[프로그래머스]주차 요금 계산 - Python (0) | 2022.05.10 |
Pololu - Tic Stepper Moto Controller (스텝모터 컨트롤러) (0) | 2022.04.29 |
[프로그래머스]신고 결과 받기 - Python (0) | 2022.04.29 |