BOJ 백준 1715 : 카드 정렬하기
Updated:
시작하면서
이번 문제는 힙(heap) 카테고리 문제이다. 저번 주차에 하지 못한 우선 순위 큐 관련 문제를 풀기 위해서 해당 문제를 골랐다.
개념
힙(heap)은 최댓값 및 최솟값을 찾아내는 연산을 빠르게 하기 위해 고안된 완전이진트리(complete binary tree)를 기본으로 한 자료구조로서 다음과 같은 힙 속성을 만족한다.
- A가 B의 부모노드이면, A의 키값과 B의 키값 사이에는 대소관계가 성립한다.
- 힙에는 두 가지 종류가 있다. 부모노드의 키값이 자식노드의 키값보다 항상 큰 힙을 ‘최대 힙’, 부모노드의 키값이 자식노드의 키값보다 항상 작은 힙을 ‘최소 힙’이라고 부른다.
- 키값의 대소관계는 오로지 부모노드와 자식노드 간에만 성립하며, 특히 형제 사이에는 대소관계가 정해지지 않는다.
- 각 노드의 자식노드의 최대개수는 힙의 종류에 따라 다르지만, 대부분의 경우는 자식노드의 개수가 최대 2개인 이진 힙(binary heap)을 사용한다.
- 힙에서는 가장 높은(혹은 가장 낮은) 우선순위를 가지는 노드가 항상 뿌리노드에 오게 되는 특징이 있으며, 이를 응용하면 우선순위 큐와 같은 추상적 자료형을 구현할 수 있다.
- 힙 (삽입의)시간복잡도는 O(logn)이다. 그 이유는 이진트리의 속성에서 힙트리의 높이 h = log(n+1) 이므로, O(logn)이다.
문제 이해
문제를 읽어보자. 먼저 이 문제에서 나오는 변수는 총 2가지이다.
- N : 숫자 카드 묶음의 개수
-
A : 숫자 카드 묶음들
이 변수를 가지고 답을 출력해야 한다.
문제 아이디어
해당 문제는 카드 묶음을 합칠 때마다 비교 횟수를 최소로 만들어야 한다. 이를 위해서는 매번 카드 묶음을 합칠 때 가장 작은 묶음 2개를 꺼내서 비교해야 한다.
- 카드 묶음의 값들을 받아서 “오름차순 우선순위 큐”에 넣어준다.
- top에서 2개의 값을 꺼내서 카드 묶음을 더해준다. 그리고 비교한 값을 세준다.
- 더해준 묶음을 다시 “오름차순 우선순위 큐”에 넣어준다.
- 위 작업들을 “오름차순 우선순위 큐”에 값이 1개가 남을 때까지 진행한다. (카드 묶음이 1개가 될 때까지)
해결
#include <iostream>
#include <queue>
using namespace std;
void Input();
void SolveProblem();
void PrintAnswer();
int N, result;
priority_queue<int, vector<int>, greater<int> > pq;
int main()
{
// sync off
ios::sync_with_stdio(false);
cin.tie(0);
Input();
SolveProblem();
PrintAnswer();
}
void Input()
{
int value;
cin >> N;
for (int i = 0; i < N; i++)
{
cin >> value;
pq.push(value);
}
}
void SolveProblem()
{
while (pq.empty() == false && pq.size() > 1)
{
int num0 = pq.top(); pq.pop();
int num1 = pq.top(); pq.pop();
int sum = num0 + num1;
result += sum;
pq.push(sum);
}
}
void PrintAnswer()
{
cout << result;
}
처음에 문제를 풀 때에는 sum을 다시 pq에 넣지 않는 실수를 했었다. 음.. 그거 말고는 따로 어려운 부분은 없었던, 우선 순위 큐를 사용하면 쉽게 풀 수 있는 문제였다.
마치며
저번 주차에 우선 순위 큐 문제를 제대로 풀지 못해 아쉬워서 한 주 더 진행했는데, 생각보다 기초 문제여서 아쉽긴 하다. 하지만 힙에 대한 개념 공부를 다시 했으니 만족한다.
Leave a comment