일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- bfs
- 이분탐색
- 1939백준
- DP
- 그래프탐색
- 이분 탐색
- 비트마스킹
- Lis
- 백준 1464
- 서로소 집합
- 깊이 우선 탐색
- 최장길이바이토닉수열
- 패스트캠퍼스
- disjoint set
- union find
- boj 1464
- 그래프 탐색
- 최장증가수열
- 브루트포스
- parametric search
- 분할정복
- 구현
- 그래프 이론
- 뒤집기 3
- 결정 문제
- 백준 뒤집기 3
- 그래프이론
- 재귀
- 결정문제
- 2493 백준
- Today
- Total
알고리즘 문제풀이
[BOJ] 1715번 - 카드 정렬하기 본문
백준 1715번 - 카드 정렬하기
시간제한 | 메모리 제한 | 제출 | 정답 | 맞은 사람 | 정답 비율 |
---|---|---|---|---|---|
2초 | 128MB | 21083 | 7277 | 5732 | 35.092% |
문제
정렬된 두 묶음의 숫자 카드가 있다고 하자. 각 묶음의 카드의 수를 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
출처
알고리즘 분류
- 자료구조
- 그리디 알고리즘
- 우선순위 큐
접근 방법
카드 묶음을 순서대로 $ s_1, s_2, s_3, ... , s_n $으로 가정하고, 매 라운드에서 ${s_k, s_{k+1}}$ 이 묶인다고 가정하자.
임의의 라운드에서 위와 같이 묶일 경우, 다음 라운드에서 총 비교 횟수는 어떻게 되는지 확인해보자.
Round 1 $= p_1$
총 비교 횟수
$(s_1 + s_2) + (s_3 + s_4) + ... + (s_{n-1} + s_n)$
Round 2 $= p_2$
총 비교 횟수
$$
{(s_1 + s_2) + (s_3 + s_4) + ... + (s_{n-1} + s_n)} \ \ + \\(s_1 + s_2 + s_3 + s_4) + (s_5 + s_6 + s_7 + s_8) + ... + (s_{n-3} + s_{n-2} + s_{n-1} + s_n)
$$
1번째 라운드에서 총 비교 횟수를 $p_1$ 이라고 하였을 때 $N$번째 라운드까지 진행하였을 때 $p_1$은 $N$번 반복하는 것을 알 수 있다. 마찬가지로 2번째 라운드에서 $p_2$는 $N-1$번 반복하는 것을 관찰할 수 있다.
즉, 각 라운드에서 필요한 총 비교 횟수 $p_k = Kp_1 + (K-1)p_2 + ... + p_k$ 임을 알 수 있다.
전체의 최적해를 얻기 위해선, $p_1 \leq p_2 \leq p_3 \leq .... \leq p_n$ 를 유지하는 것이 중요하다.
이를 위해 각 라운드에서 선택할 수 있는 최소의 $s_k, s_{k+1}$를 선택하는 것이 중요하다.
N의 최대 값이 $10^5$라는 것을 고려하였을 때 $O(logN)$내에 최소 원소 2개를 선택하기 위해, Min heap을 이용하는 것이 핵심이다.
+ 소스코드 설명
아래 소스코드에서 while문 내부에서 최소값인 2개의 원소를 꺼내서 합한 다음, 1개의 원소를 삽입하여 loop를 진행하므로 priority_queue
내부의 원소의 개수는 linear하게 1씩 감소하는 것을 확인할 수 있다. 큐 내부에 원소가 $N(1 \leq N \leq 100,000)$인 것을 고려해보았을 때, 해당 알고리즘의 종료성을 확인할 수 있을 것이다.
소스코드
#define FASTIO cin.tie(0)->sync_with_stdio(false), cout.tie(0)
#include <bits/stdc++.h>
using namespace std;
int N;
int main(void){
FASTIO;
//////////////////////////////////////////////////////////////////
cin >> N;
vector<long long> v(N);
for(auto &item : v)
cin >> item;
long long ans = 0;
priority_queue<long long, vector<long long>, greater<long long>> PQ;
for(const auto &item : v)
PQ.push(item);
while(PQ.size() > 1){
long long a, b;
a = PQ.top(), PQ.pop();
b = PQ.top(), PQ.pop();
ans += (a + b);
PQ.push(a + b);
}
cout << ans ;
return 0;
}
'자료구조 + 알고리즘 > [BOJ]' 카테고리의 다른 글
[BOJ] 16472번 - 고냥이 (0) | 2021.12.31 |
---|---|
[BOJ] 1240번 - 노드사이의 거리 (0) | 2021.12.31 |
[BOJ] 15992번 - 1,2,3 더하기 7 (0) | 2021.12.30 |
[BOJ] 10749번 - Superbull (0) | 2021.12.30 |
[BOJ] 13334번 - 철로 (0) | 2021.08.30 |