본문 바로가기

백준

[백준]1715번 - 카드 정렬하기

문제

정렬된 두 묶음의 숫자 카드가 있다고 하자. 각 묶음의 카드의 수를 A, B라 하면 보통 두 묶음을 합쳐서 하나로 만드는 데에는 A+B 번의 비교를 해야 한다. 이를테면, 20장의 숫자 카드 묶음과 30장의 숫자 카드 묶음을 합치려면 50번의 비교가 필요하다.

매우 많은 숫자 카드 묶음이 책상 위에 놓여 있다. 이들을 두 묶음씩 골라 서로 합쳐나간다면, 고르는 순서에 따라서 비교 횟수가 매우 달라진다. 예를 들어 10장, 20장, 40장의 묶음이 있다면 10장과 20장을 합친 뒤, 합친 30장 묶음과 40장을 합친다면 (10 + 20) + (30 + 40) = 100번의 비교가 필요하다. 그러나 10장과 40장을 합친 뒤, 합친 50장 묶음과 20장을 합친다면 (10 + 40) + (50 + 20) = 120 번의 비교가 필요하므로 덜 효율적인 방법이다.

N개의 숫자 카드 묶음의 각각의 크기가 주어질 때, 최소한 몇 번의 비교가 필요한지를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (1 ≤ N ≤ 100,000) 이어서 N개의 줄에 걸쳐 숫자 카드 묶음의 각각의 크기가 주어진다. 숫자 카드 묶음의 크기는 1,000보다 작거나 같은 양의 정수이다.

출력

첫째 줄에 최소 비교 횟수를 출력한다.

예제 입력 1 

3
10
20
40

예제 출력 1 

100

 

문제 풀이 

1. 가장 작은 묶음부터 합쳐야 한다: 카드 묶음을 합칠 때마다 비교 횟수가 발생하고, 합쳐진 묶음은 다음 단계의 연산에 계속 포함됩니다. 즉, 초반에 합친 카드 묶음의 크기가 작을수록, 전체 비교 횟수가 줄어듭니다.

  • 예를 들어 10, 20, 40이 있을 때:
    • (10+20)을 먼저 하면: 30이 됨. (비용 30 발생) → 남은 것: 30, 40
    • (30+40)을 하면: 70이 됨. (비용 70 발생)
    • 총 비용: 30 + 70 = 100
  • 만약 큰 것(20+40)을 먼저 하면:
    • (20+40)을 먼저 하면: 60이 됨. (비용 60 발생) → 남은 것: 10, 60
    • (10+60)을 하면: 70이 됨. (비용 70 발생)
    • 총 비용: 60 + 70 = 130 (더 비효율적)

따라서 현재 나와 있는 카드 묶음 중 가장 작은 2개를 계속해서 선택해야 합니다.

2. 자료구조 선택: 우선순위 큐

 매번 가장 작은 값 2개를 찾고, 합친 결과를 다시 넣어서 정렬해야 합니다. 일반 리스트를 매번 정렬하면 시간 복잡도가 너무 커져서 시간 초과가 납니다. 따라서 삽입/삭제 시 자동으로 정렬 상태를 유지해 주는 heapq (최소 힙)를 사용해야 합니다.

 

 

답안 코드

import sys
import heapq

# 1. 입력 받기
input = sys.stdin.readline
N = int(input())

cards = []

for _ in range(N):
    heapq.heappush(cards, int(input()))

# 2. 그리디 알고리즘 
total_cost = 0

# 카드 묶음이 1개만 남을 때까지 반복
while len(cards) > 1:
    # 가장 작은 묶음 2개 꺼내기 pop
    first = heapq.heappop(cards)
    second = heapq.heappop(cards)
    
    # 두 묶음을 합침
    sum_val = first + second
    
    # 비교 횟수 누적
    total_cost += sum_val
    
    # 합친 묶음을 다시 힙에 넣기 push
    heapq.heappush(cards, sum_val)

print(total_cost)

 

코드 설명

  1. heapq.heappush: 입력받은 카드 묶음들을 힙에 넣습니다. 파이썬의 heapq는 기본적으로 최소 힙(Min-Heap)이므로, 가장 작은 숫자가 항상 0번째 인덱스(루트)에 오게 됩니다.
  2. while len(cards) > 1: 묶음이 하나로 합쳐질 때까지 반복합니다.
  3. heappop 2번: 가장 작은 카드 묶음(first)과 두 번째로 작은 카드 묶음(second)을 꺼냅니다.
  4. total_cost += sum_val: 두 묶음을 합치는 데 발생한 비용을 전체 비용에 더합니다.
  5. heappush(cards, sum_val): 합쳐진 새 묶음도 나중에 다른 묶음과 합쳐져야 하므로, 다시 힙에 넣습니다. 이때 힙은 자동으로 크기 순서를 재정렬합니다.
  6. 예외 처리 일 경우, 비교할 대상이 없으므로 비교 횟수는 0입니다. 위 코드는 while len(cards) > 1 조건 덕분에 일 때 루프를 돌지 않고 0을 올바르게 출력하므로 별도의 예외 처리를 하지 않아도 됩니다.

'백준' 카테고리의 다른 글

[프로그래머스] 양궁대회  (1) 2026.02.11
[백준] 14719번 - 빗물  (0) 2026.02.10
[백준] 2493번 - 탑  (0) 2026.02.09
[프로그래머스] 이모티콘할인행사  (0) 2026.02.09
[백준] 1863번 - 스카이라인 쉬운거  (0) 2026.02.07