두 사람이 노래의 N개 음을 나누어 부를 때, 두 사람이 느끼는 난이도의 합을 최소화하는 문제이다. 각 사람의 난이도는 연속으로 부른 음의 차이의 합으로 정의되며, DP로 최적 배분을 구할 수 있다.
문제 정보
문제 링크: https://www.acmicpc.net/problem/12932
문제 요약:
- 음의 높이는 1부터 1,000,000까지의 정수로 표현된다.
- 노래는 N개의 음이 순서대로 주어진다.
- 각 음은 두 사람 중 한 사람만 부른다.
- 각 사람의 난이도 = 연속으로 부른 음들의 차이의 합 (예: 8, 8, 13, 12를 부르면 |8-8| + |13-8| + |12-13| = 6)
- 두 사람 난이도의 합의 최솟값을 구한다.
제한 조건:
- 시간 제한: 2초
- 메모리 제한: 512MB
- $1 \le N \le 2{,}000$
입출력 예제
입력 1:
| |
출력 1:
| |
설명: 영선이가 1, 3을 부르고 효빈이가 8, 12, 13을 부르면 영선 난이도 2 + 효빈 난이도 5 = 7이다.
입력 2:
| |
출력 2:
| |
입력 3:
| |
출력 3:
| |
접근 방식
핵심 관찰
- 같은 사람이 연속으로 부른 음들 사이에만 비용이 발생한다. 다른 사람이 부른 음이 끼어 있으면 그 구간은 비용에 포함되지 않는다.
- 따라서 각 음을 순서대로 처리하면서, “누가 k번째 음을 부르는가"를 결정할 때, 그 사람이 직전에 부른 음의 인덱스만 알면 새로 추가되는 비용 |a[k] - a[last]|를 계산할 수 있다.
- 이 문제는 최적 부분 구조를 가지므로 DP로 접근 가능하다.
알고리즘 설계 (Mermaid Flowchart)
flowchart TD
A["시작: N, a[0..N-1] 입력"] --> B["dp[-1,-1] = 0 초기화"]
B --> C["k = 0..N-1 순회"]
C --> D{"k번째 음 배정"}
D -->|"사람 0이 부름"| E["비용 += |a[k]-a[last0]| (last0 존재 시)"]
D -->|"사람 1이 부름"| F["비용 += |a[k]-a[last1]| (last1 존재 시)"]
E --> G["ndp[k, last1] 갱신"]
F --> H["ndp[last0, k] 갱신"]
G --> I{"k < N-1?"}
H --> I
I -->|"예"| C
I -->|"아니오"| J["min(dp 모든 상태) 출력"]
단계별 로직
- 상태 정의:
dp[last0][last1]= 0..k-1번 음까지 처리했을 때의 최소 총 난이도.last0는 사람 0이 마지막으로 부른 음의 인덱스,last1은 사람 1의 것. (-1이면 아직 부른 적 없음) - 전이: k번째 음을 사람 0이 부르면
last0→ k, 비용에 |a[k]-a[last0]| 추가 (last0 ≥ 0일 때). 사람 1이 부르면last1→ k, 비용에 |a[k]-a[last1]| 추가. - 유효 상태: k번째 음까지 처리한 상태에서는 반드시
last0 = k또는last1 = k이어야 하므로, 이전 단계에서last0 = k-1또는last1 = k-1인 상태만 전이에 사용한다. - 답: 모든 음 처리 후
dp의 최솟값.
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | $O(N^2)$ | 각 단계에서 상태 수 $O(N)$, 총 $N$ 단계 |
| 공간 복잡도 | $O(N^2)$ | map으로 유효 상태만 저장 시 실제로는 $O(N)$ 수준 |
구현 코드
C++
| |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| N=1 | 한 음만 있을 때 | 한 사람이 부르면 비용 0, 정상 처리됨 |
| 모든 음이 동일 | 예제 3처럼 5,5,5,5,4,4,4,4 | 같은 음 연속이면 |차이|=0, 답 0 |
| 오버플로우 | N=2000, 음 차이 최대 10^6일 때 | long long 사용으로 충분 |
| 상태 폭발 | 2D 배열 사용 시 | map으로 유효 상태만 저장해 메모리 절약 |
![Featured image of post [Algorithm] C++ 백준 12932번: 노래방](/post/algorithm/2026-02-24-boj-12932-karaoke/wordcloud_hu_e04342661cf07b79.webp)
![[Algorithm] C++ 백준 12932번: 노래방](/post/algorithm/2026-02-24-boj-12932-karaoke/wordcloud_hu_1f0c8ee66631427c.webp)
![[Algorithm] C++ 백준 16879번: 궁전 게임](/post/algorithm/2026-02-23-boj-16879-palace-game-grundy-cpp-solution/wordcloud_hu_1c61cc44e16b2b69.webp)
![[Algorithm] C++ 백준 17408번: 수열과 쿼리 24](/post/algorithm/2026-02-23-boj-17408-sequence-and-query-24-segment-tree-cpp-solution/wordcloud_hu_af2d4d2a8fdc290e.webp)
![[Algorithm] C++ 백준 4297번: Ultra-QuickSort](/post/algorithm/2026-02-23-boj-4297-ultra-quicksort-inversion-count-bit-cpp-solution/wordcloud_hu_b39e25d7aac45cef.webp)
![[Algorithm] C++ 백준 17481번: 최애 정하기](/post/algorithm/2026-02-06-boj-17481-favorite-member-bipartite-matching-hopcroft-karp-cpp-solution/wordcloud_hu_44b3c5d534a357d8.webp)
![[Algorithm] C++/Python 백준 1126번 : 같은 탑](/post/algorithm/2025-02-10-boj-1126/index_hu_106e3e671c62ed4d.webp)
![[Algorithm] C++/Python 백준 1014번 : 컨닝](/post/algorithm/2024-09-23-boj-1014/tmp_wordcloud_hu_b3c868c2d5a7f65c.webp)
![[Algorithm] C++/Python 백준 2618번 : 경찰차](/post/algorithm/2024-09-23-boj-2618/tmp_wordcloud_hu_b516fba37f0a7dd4.webp)
![[Algorithm] C++ 백준 5498번: Batch Scheduling](/post/algorithm/2025-12-19-boj-5498-batch-scheduling-cpp-solution/wordcloud_hu_e4937b19a9dbf185.webp)
![[Algorithm] C++ 백준 13974번: 파일 합치기 2](/post/algorithm/2025-08-14-boj-13974-file-merge-2-cpp-solution/wordcloud_hu_61ba7c3aae80827c.webp)