이 글에서는 단순히 "45분 당기기"만 처리하는 백준 2884번*의 기본 풀이를 넘어, 어떤 시간 조정(조기상 / 늦잠) 상황에서도 정확하게 동작하는 일반화된 알람 계산 방식을 파이썬으로 구현해 보겠습니다.
☞ 백준문제 2884번 (단계별로 풀어보기 - 조건문 5번: 알람 시계) https://www.acmicpc.net/problem/2884
구현을 위한 핵심 아이디어는 하루를 0~1439분의 순환 구조로 보고 모든 시각을 하나의 "분 인덱스"로 다루는 것입니다. 이렇게 관점을 잡으면 시·분 경계, 하루 넘어감(23:59 → 00:00) 같은 문제점이 해결됩니다.
1. 백준 2884번 "알람 시계" 문제의 아쉬운 점
백준 2884번(알람 시계)는 현재 시간에서 45분을 "당겨서" 설정하는 간단한 조건문 문제입니다.
- 입력: 현재 시간 H M (0 ≤ H ≤ 23, 0 ≤ M ≤ 59)
- 출력: 45분 "이전" 시간
그래서 많은 풀이가 예제 1, 2, 3만 통과하도록 작성되고, 자연스럽게 "45분 당기기"라는 특수 상황에만 맞춰져 있습니다.
예를 들어 아래와 같은 풀이가 보통 답안(solution)입니다.
# 입력 시간 = 알람 셋팅 시간 [hh:mm]
data = input().split()
h = int(data[0]) # 시
m = int(data[1]) # 분
# 일찍 당길 시간 크기 [hh:mm], 당기는 의미를 적용하여 시, 분을 음수로 설정
dh, dm = [0, -45] # [시:분]
# 셋팅 시간보다 당겨진 시간의 시(h), 분(m)
h = h + dh
m = m + dm
# 출력 시간 계산
if m >= 0:
pass
elif m < 0:
if h - 1 >= 0:
h = h - 1
m = m + 60
else: # h - 1 < 0, 즉 h == 0
h = h - 1 + 24
m = m + 60
print(h, m)
"""
# 예제 입력 1
10 10
# 예제 출력 1
9 25
# 예제 입력 2
0 30
# 예제 출력 2
23 45
# 예제 입력 3
23 40
# 예제 출력 3
22 55
"""
이 코드는 "45분 빼기(음수 이동)"라는 단일 상황에서는 잘 작동합니다. 하지만 문제의 주어진 입력값에만 부합하는 "틀"을 벗어나서 "시간을 늦춰보기(양수 이동)"를 시도하면, 위 코드 만으로는 정답과 부합하지 않는 한계가 드러납니다.
2. 45분 "늦추기"를 해보면 생기는 문제
위 구조를 그대로 가져와서, 이번에는 "45분을 늦춰보기(더하기)"로 바꿔 보겠습니다.
# 입력 시간 = 알람 셋팅 시간 [hh:mm]
data = input().split()
h = int(data[0]) # 시
m = int(data[1]) # 분
# 늦추어질 시간 크기 [hh:mm], 늦추는 의미를 적용하여 시, 분을 양수로 설정
dh, dm = [0, 45] # [시:분]
h = h + dh
m = m + dm
if m >= 0:
pass
elif m < 0:
if h - 1 >= 0:
h = h - 1
m = m + 60
else:
h = h - 1 + 24
m = m + 60
print(h, m)
"""
# 예제 입력
23 20
# 실제 출력
23 65 ← 60분을 초과하는 잘못된 분 표시
"""
여기서 문제가 되는 핵심은 다음과 같습니다.
- 분이 60 이상이 되면, 시[h]를 1 증가시키고, 분[m]에서 60을 빼야 합니다.
- 하지만 이 코드는 “분이 음수일 때만” 보정하도록 되어 있기 때문에 분이 60을 넘는 경우는 정상적으로 연산하지 못합니다.
즉, 이 코드의 한계(문제)는 다음과 같습니다.
- "45분 당기기"라는 백준 2884의 좁은 조건 안에서는 괜찮지만,
- "알람 시간을 자유롭게 앞/뒤로 조정한다"는 일반적인 관점에서는 불안정한 코드입니다.
이제 이 한계를 극복하기 위해서 일반화된 방식으로 코드를 구현해 보겠습니다.
3. 하루 전체를 "분 인덱스"로 보는 아이디어
시간 계산을 안정적으로 처리하기 위한, 즉 코드를 일반화시키기 위한 아이디어는 다음과 같습니다.
- 하루 = 24시간 × 60분 = 1440분
- 시, 분 [h, m]을 하나의 정수 인덱스로 변환
→ index = h * 60 + m (0 ≤ index ≤ 1439) - "시간을 당기거나(음수), 늦추는(양수)" 것은
→ index에 음수/양수를 더하는 연산으로 통일 - 하루는 ‘순환’이므로
→ "모듈러 연산 % 1440"으로 처리
이것을 수식으로 요약하면:
old_index = h * 60 + m
new_index = (old_index + 이동분량_분) % 1440
- 알람 시간보다 일찍 일어나기 위한 알람 설정 → 음수 이동 (조기상)
- 알람 시간보다 늦게 일어나기 위한 알람 설정 → 양수 이동 (늦잠)
- 시·분 경계(59분 → 00분, 23시 → 0시)
- 하루 넘어감(23:59 → 00:00)
즉, 모든 경우가 같은 규칙, 한 줄짜리 수식으로 해결됩니다.
이 아이디어를 적용하면, 모든 알람 시간 세팅에 부합하는 일반화된 "알람 계산기"를 구현할 수 있습니다.
4. 일반화 코드: 조기상(음수) + 늦잠(양수) 완전 지원
아래 코드는 "알람 초기 시간 + 변경 시간(조기상/늦잠)"을 입력받아서, 변경된 알람 시간을 계산하는 일반화된 코드입니다.
# 알람 시간 일반화 계산기
# - 알람 초기 시간 (h_initial, m_initial)
# - 변경할 시간 크기 (dh, dm) ← 조기상: 음수 / 늦잠: 양수
def compute_alarm(h_initial, m_initial, dh, dm):
"""알람 시간을 dh시간 dm분 만큼 이동시킨 결과를 반환한다."""
# 1. 현재 시간을 '하루 기준 분 단위'로 변환 (0 ~ 1439)
total = h_initial * 60 + m_initial
# 2. 움직일 총 분량 (음수/양수 모두 허용)
diff = dh * 60 + dm
# 3. 하루(24*60분) 기준으로 순환 이동
new_total = (total + diff) % (24 * 60)
# 4. 다시 시/분으로 변환
new_h = new_total // 60
new_m = new_total % 60
return new_h, new_m
def main():
# 초기 알람 시간 입력
h_initial, m_initial = map(int, input('알람 설정 시간 [hh mm] = ').split())
# 변경할 시간 크기 입력 (음수: 조기상, 양수: 늦잠)
dh, dm = map(int, input('변경할 시간 크기 [hh mm] = ').split())
# 알람 계산
set_hour, set_mins = compute_alarm(h_initial, m_initial, dh, dm)
# 결과 출력
print()
print(f'셋팅한 초기 알람 시간 = {h_initial} {m_initial}')
print(f'움직인 시간 [hh:mm] = {dh} {dm}')
print(f'변경된 알람 시간 = {set_hour} {set_mins}')
if __name__ == "__main__":
main()
예시 1: 늦잠(양수 이동)
알람 설정 시간 [hh mm] = 23 50
변경할 시간 크기 [hh mm] = 1 20
셋팅한 초기 알람 시간 = 23 50
움직인 시간 [hh:mm] = 1 20
변경된 알람 시간 = 1 10
- 23:50에서 1시간 20분 늦잠 → 01:10으로 정확히 계산됩니다.
예시 2: 조기상(음수 이동)
알람 설정 시간 [hh mm] = 0 45
변경할 시간 크기 [hh mm] = -1 -25
셋팅한 초기 알람 시간 = 0 45
움직인 시간 [hh:mm] = -1 -25
변경된 알람 시간 = 23 20
- 00:45에서 1시간 25분 당겨서(조기상) → 전날 23:20으로 정확히 연산됩니다.
- 하루 24시가 "순환"하도록 % (24*60)으로 처리했기 때문에 가능한 결과입니다.
5. 핵심 포인트 한 번 더 짚어보기
5-1. 시·분 단위 통일
- dh: 시간 단위 이동량
- dm: 분 단위 이동량
시와 분을 "분" 단위 하나로 통합하면 (1시간 → 60분), 수식이 단순해집니다.
diff = dh * 60 + dm
- dh = -1, dm = -45 → diff = -60 - 45 = -105분
- dh = 1, dm = 20 → diff = 60 + 20 = 80분
시·분이라는 2차원 개념을 "한 줄짜리 선(분)" 위에서의 이동량으로 바꾼 것입니다.
5-2. 하루를 0~1439분으로 바꾸기
이제 모든 시각을 0~1439 사이의 정수로 다룸으로써, 시간 계산이 단순한 정수 덧셈 문제로 바뀝니다.
total = h_initial * 60 + m_initial
- 00:00 → 0분
- 00:01 → 1분
- 01:00 → 60분
- 23:59 → 23*60 + 59 = 1439분
5-3. 하루 순환 처리
- (total + diff)만 사용하면 음수가 될 수도 있고 1440을 넘어서 리스트 범위를 벗어날 수도 있습니다.
- % (24*60)을 붙여 줌으로써 항상 0 ≤ new_total ≤ 1439 범위 안으로 “순환”시킵니다.
new_total = (total + diff) % (24 * 60)
- total = 0, diff = -1 → (0 - 1) % 1440 = 1439 → 23:59
- total = 1435, diff = 10 → (1435 + 10) % 1440 = 1445 % 1440 = 5 → 00:05
이렇게 한 줄로 구성하면, 전날 또는 다음날로 넘어가는 상황까지 모두 해결됩니다.
5-4. 다시 시·분으로 되돌리기
new_h = new_total // 60
new_m = new_total % 60
- 정수 나눗셈(//)으로 시(hour), 나머지(%) 연산으로 분(minute)을 구합니다.
- 이렇게 하여, “백준 2884의 45분 당기기”는 물론이고, “임의의 시간/분만큼 앞뒤로 움직이기”라는 일반적인 알람 계산이 모두 안정적으로 처리됩니다.
6. 백준 2884번에 다시 적용해 보기 (단순화 버전)
위에서 살펴본 일반화 아이디어를 그대로 적용하면, 백준 제출용 코드는 오히려 더 짧고 간단해집니다.
H, M = map(int, input().split())
# 1. 현재 시각을 '전체 분'으로 변환
total = H * 60 + M
# 2. 45분 당기기 → -45분 이동
total = (total - 45) % (24 * 60)
# 3. 다시 시/분으로 변환
print(total // 60, total % 60)
- 조건문 없이, 시/분 경계 고민 없이, 경계값(0시, 0분 등)까지 깔끔하게 처리할 수 있습니다.
이 코드는 "하루 전체를 분으로 보고, 모듈러 연산으로 순환하는" 앞에서 설명한 일반화 아이디어를 간결하게 구현했습니다.
7. 글을 맺으며
- 단순히 조건문으로 예제만 해결하는 방식을 넘어서, 하루 전체를 0~1439분의 순환 구조로 바라보면 시간 조정이 훨씬 간결하고 안정적으로 처리됩니다.
- 이렇게 시·분의 경계를 고민하지 않고도 **조기상(음수 이동)**과 **늦잠(양수 이동)**을 모두 하나의 규칙으로 계산할 수 있다는 점이 핵심입니다.
- 백준 2884번은 이러한 시간·모듈러 방식을 연습하기 좋은 사례이며, 실제 알람 앱이나 스케줄러 기능을 설계할 때도 그대로 적용할 수 있는 실용적인 개념을 연습하기에도 좋은 문제입니다.
즐거운 파이썬, 즐 파이씽~
[주의] 내용에 오류가 있을 수 있습니다.

'[Code] Study & Practice' 카테고리의 다른 글
| [Python] 탐색 알고리즘의 개념: 선형(Linear), 이진(Binary), 깊이 우선(DFS), 너비 우선(BFS) (0) | 2025.11.27 |
|---|---|
| [Python] 정렬 알고리즘(sorts)과 동적 프로그래밍(DP)의 개념: 시간 복잡도, Big-O (0) | 2025.11.22 |
| [HTML,CSS] tistroy, 제목 글자 크기 수정하기 (0) | 2025.11.09 |
| [Python] MySQL & Jupyter 연동 - 객체지향 프로그래밍(OOP)을 활용한 DB 작업 프로그램 예제 (0) | 2025.11.05 |
| [Python] 자료 구조5 - 힙(Heap)의 개념, 구조, 규칙 (0) | 2025.11.01 |