Algorithm/코딩테스트

[백준 2730] 오늘은 OS 숙제 제출일

이숨인 2024. 8. 26. 16:49

🍉문제

 

 

 

🍉문제 해석

숙제 마감일과 제출일이 주어졌을 때, 제출일이 마감일에 비해 얼마나 이전인지 또는 이후인지를 판단하고, 결과를 적절히 출력하는 문제이다.

 

** 제출일에는 연도가 명시되지 않기 때문에, 가장 가까운 연도를 추정하여 비교를 수행하도록 하였다!

이 부분이 가장 까다로웠던 부분인 듯 하다.

 

🍉문제 접근법

1. 윤년과 월별 일수 처리

 

  • 윤년을 고려하여 월별 일수를 정확히 계산해야 했다.
  • 2월의 경우, 윤년에 따라 28일 또는 29일을 반환하는 것을 잊지 말자!
  • days_in_month 함수로 구현하였다.
thirty_days_month = [4, 6, 9, 11]
thirty_one_days_month = [1, 3, 5, 7, 8, 10, 12]

def days_in_month(month, year):
    if month in thirty_days_month:
        return 30
    elif month in thirty_one_days_month:
        return 31
    else:  # February
        if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0):
            return 29
        else:
            return 28

 

2. 날짜를 일수로 변환

 

  • 비교를 위해 날짜를 연도(year),월(month)을 기준으로 총 일수로 변환해야 한다.
  • 이 과정에서 모든 연도의 일수를 누적하도록 하였다
  • date_to_days_total 함수를 통해 구현하였다.
def date_to_days_total(day, month, year):
    days = 0
    # 1. (현재 연도의 이전 연도까지)연도에 대해 일수를 누적한다. 윤년을 고려한다
    for y in range(1, year):
        days += 366 if y % 4 == 0 and (y % 100 != 0 or y % 400 == 0) else 365
  
  # 2. 현재 연도의 월에 대해 일수를 누적한다. 앞에서 정의한 days_in_month함수를 통해 윤년을 고려하도록 하였다.
    for m in range(1, month):
        days += days_in_month(m, year)
    
    # 3. 현재 월에 일수를 더한다
    days += day
    return days

 

 

3. 날짜를 문자열로 변환

 

월, 일, 연도를 문자열로 변환하여 반환하는 함수를 구현하였다.

월과 일의 선행 0은 자동으로 제거된다

 

def datetime_to_string(month, day, year):
    return f'{month}/{day}/{year}'

 

 

 

4. 제출일과 마감일 비교

 

handle_dates 함수는 제출일과 마감일을 비교하여, 제출일이 마감일에 비해 얼마나 이른지 또는 늦은지를 판단하고, 

상황에 따라 다른 메시지를 반환하는 역할을 한다. 

def handle_dates(deadline_str, submission_str):
    d_month, d_day, d_year = map(int, deadline_str.split('/'))
    s_month, s_day = map(int, submission_str.split('/'))
    
    # 마감일과 제출일을 일수로 변환
    total_deadline = date_to_days_total(d_day, d_month, d_year)
    
    # 제출일의 연도를 추정하여 두 가지 경우를 처리
    possible_years = [d_year - 1, d_year, d_year + 1]
    closest_submission_date = None
    closest_gap = float('inf')
    
    for year in possible_years:
        total_submission = date_to_days_total(s_day, s_month, year)
        gap = total_submission - total_deadline
        if abs(gap) < abs(closest_gap):
            closest_gap = gap
            closest_submission_date = (s_month, s_day, year)
    
    # 날짜 차이 계산
    s_month, s_day, s_year = closest_submission_date
    gap = closest_gap
    
    if gap > 0:
        if 1 < gap <= 7:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAYS AFTER'
        elif gap == 1:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAY AFTER'
        else:
            return "OUT OF RANGE"
    elif gap < 0:
        gap = -gap
        if 1 < gap <= 7:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAYS PRIOR'
        elif gap == 1:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAY PRIOR'
        else:
            return "OUT OF RANGE"
    else:
        return "SAME DAY"

 

이번 문제의 핵심 로직을 담고있는 handle_dates는 위와 같다. 이제 코드를 분석해보자

 

1) 함수 정의 및 매개변수

 

  • deadline_str: 마감일을 나타내는 문자열로, MM/DD/YYYY 형식이다
  • submission_str: 제출일을 나타내는 문자열로, MM/DD 형식이다
total_deadline = date_to_days_total(d_day, d_month, d_year)

 

 

2)마감일을 일수로 변환

total_deadline = date_to_days_total(d_day, d_month, d_year)

 

3) 제출일의 연도를 추정하여 비교

possible_years = [d_year - 1, d_year, d_year + 1]
closest_submission_date = None
closest_gap = float('inf')

 

  • 제출일의 연도는 명시되지 않으므로, 마감일의 전년도, 해당 연도, 다음 년도를 가능한 연도로 설정하여 제출일을 비교하여 결정한다.
  • closest_submission_date는 가장 가까운 제출일을 저장할 변수이다
  • closest_gap은 마감일과 제출일 간의 차이를 저장하며, 초기값으로 무한대를 설정하여 이후에 실제 차이로 대체하도록 한다.

4) 가능한 연도에 대한 제출일 비교

for year in possible_years:
    total_submission = date_to_days_total(s_day, s_month, year)
    gap = total_submission - total_deadline
    if abs(gap) < abs(closest_gap):
        closest_gap = gap
        closest_submission_date = (s_month, s_day, year)

 

  • 각 가능한 연도에 대해 제출일을 일수로 변환하고, 마감일과의 차이를 계산한다
  • 가장 작은 차이를 가진 제출일을 closest_submission_date에 저장한다

 

5) 날짜 차이 계산 및 결과 반환

s_month, s_day, s_year = closest_submission_date
gap = closest_gap

 

  • 최종적으로 가장 가까운 제출일을 s_month, s_day, s_year로 저장하고, 차이를 gap으로 설정한다.
  • 제출일이 마감일보다 늦은 경우 , 제출일이 마감일보다 이른 경우, 마감일과 제출일이 같은 경우 세 가지 경우로 구분하여 출력한다
 if gap > 0: #제출일이 마감일보다 늦은 경우
        if 1 < gap <= 7:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAYS AFTER'
        elif gap == 1:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAY AFTER'
        else:
            return "OUT OF RANGE"
    elif gap < 0: #제출일이 마감일보다 이른 경우
        gap = -gap
        if 1 < gap <= 7:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAYS PRIOR'
        elif gap == 1:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAY PRIOR'
        else:
            return "OUT OF RANGE"
    else: #마감일과 제출일이 같은 경우
        return "SAME DAY"

 

🍉전체 코드

# 월별 일수와 윤년 처리
thirty_days_month = [4, 6, 9, 11]
thirty_one_days_month = [1, 3, 5, 7, 8, 10, 12]

def days_in_month(month, year):
    if month in thirty_days_month:
        return 30
    elif month in thirty_one_days_month:
        return 31
    else:  # February
        if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0):
            return 29
        else:
            return 28

def date_to_days_total(day, month, year):
    days = 0
    # Add days for years
    for y in range(1, year):
        days += 366 if y % 4 == 0 and (y % 100 != 0 or y % 400 == 0) else 365
    # Add days for months in the current year
    for m in range(1, month):
        days += days_in_month(m, year)
    # Add days in the current month
    days += day
    return days

def datetime_to_string(month, day, year):
    # Convert to string without leading zeros
    return f'{month}/{day}/{year}'

def handle_dates(deadline_str, submission_str):
    d_month, d_day, d_year = map(int, deadline_str.split('/'))
    s_month, s_day = map(int, submission_str.split('/'))
    
    # 마감일과 제출일을 일수로 변환
    total_deadline = date_to_days_total(d_day, d_month, d_year)
    
    # 제출일의 연도를 추정하여 두 가지 경우를 처리
    possible_years = [d_year - 1, d_year, d_year + 1]
    closest_submission_date = None
    closest_gap = float('inf')
    
    for year in possible_years:
        total_submission = date_to_days_total(s_day, s_month, year)
        gap = total_submission - total_deadline
        if abs(gap) < abs(closest_gap):
            closest_gap = gap
            closest_submission_date = (s_month, s_day, year)
    
    # 날짜 차이 계산
    s_month, s_day, s_year = closest_submission_date
    gap = closest_gap
    
    if gap > 0:
        if 1 < gap <= 7:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAYS AFTER'
        elif gap == 1:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAY AFTER'
        else:
            return "OUT OF RANGE"
    elif gap < 0:
        gap = -gap
        if 1 < gap <= 7:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAYS PRIOR'
        elif gap == 1:
            return f'{datetime_to_string(s_month, s_day, s_year)} IS {gap} DAY PRIOR'
        else:
            return "OUT OF RANGE"
    else:
        return "SAME DAY"

# 입력을 처리하는 부분
N = int(input())
results = []

for _ in range(N):
    deadline, submission = input().split()
    result = handle_dates(deadline, submission)
    results.append(result)
    
# 결과 출력
for result in results:
    print(result)