[BOJ][⚪1][백준#15903] 카드 합체 놀이

작성:    

업데이트:

카테고리:

태그: , , ,

문제 출처

BAEKJOON Online Judge #15903


문제

석환이는 아기다. 아기 석환이는 자연수가 쓰여져있는 카드를 갖고 다양한 놀이를 하며 노는 것을 좋아한다. 오늘 아기 석환이는 무슨 놀이를 하고 있을까? 바로 카드 합체 놀이이다! 아기 석환이는 자연수가 쓰여진 카드를 n장 갖고 있다. 처음에 i번 카드엔 ai가 쓰여있다. 카드 합체 놀이는 이 카드들을 합체하며 노는 놀이이다. 카드 합체는 다음과 같은 과정으로 이루어진다.

x번 카드와 y번 카드를 골라 그 두 장에 쓰여진 수를 더한 값을 계산한다. (x ≠ y) 계산한 값을 x번 카드와 y번 카드 두 장 모두에 덮어 쓴다.

이 카드 합체를 총 m번 하면 놀이가 끝난다. m번의 합체를 모두 끝낸 뒤, n장의 카드에 쓰여있는 수를 모두 더한 값이 이 놀이의 점수가 된다. 이 점수를 가장 작게 만드는 것이 놀이의 목표이다. 아기 석환이는 수학을 좋아하긴 하지만, 아직 아기이기 때문에 점수를 얼마나 작게 만들 수 있는지를 알 수는 없었다(어른 석환이는 당연히 쉽게 알 수 있다). 그래서 문제 해결 능력이 뛰어난 여러분에게 도움을 요청했다. 만들 수 있는 가장 작은 점수를 계산하는 프로그램을 만들어보자.


입력

첫 번째 줄에 카드의 개수를 나타내는 수 n(2 ≤ n ≤ 1,000)과 카드 합체를 몇 번 하는지를 나타내는 수 m(0 ≤ m ≤ 15×n)이 주어진다. 두 번째 줄에 맨 처음 카드의 상태를 나타내는 n개의 자연수 a1, a2, …, an이 공백으로 구분되어 주어진다. (1 ≤ ai ≤ 1,000,000)


출력

첫 번째 줄에 만들 수 있는 가장 작은 점수를 출력한다.


예제

예제 1

입력

3 1
3 2 6


출력

16


예제 2

입력

4 2
4 2 3 1


출력

19


My Sol

import sys
input = sys.stdin.readline
from heapq import heappop, heappush

n, m = map(int, input().split())
h = []
for a in list(map(int, input().split())):
    heappush(h, a)

for _ in range(m):
    a = heappop(h)
    b = heappop(h)
    heappush(h, a+b)
    heappush(h, a+b)

print(sum(h))

배열의 크기가 작아 매번 정렬을 해서 2개를 빼내고, 이를 더해 2개를 더해도 되겠지만, 합체의 횟수 m이 최돼 15xn라면, 최대 n은 1000이므로 15000을 반복하게 된다. 이때 매번 정렬을 하게 되면 정렬 시간이 폭증하게 될 것이다. 때문에 최소 힙을 이용해 문제를 해결했다.

정렬에 있어 일반적인 정렬은 O(N2)의 시간복잡도를 가지고 힙 정렬은 O(NlogN)의 시간복잡도를 가진다. 트리형태로 거슬러 올라가기 때문에 절반에 대해 확인하지 않기 때문이다. 때문에 배열의 크기가 크지는 않지만 반복의 횟수가 많은 경우이므로 차이를 줄이기 위해 heap을 사용한다.

힙은 기본적으로 최소힙이므로 가장 작은 2개의 값을 h로부터 빼내고, 이 둘을 더한 값을 2번 heappush 해준다. 이 사이에 크기에 따라 자동으로 정렬해준다.


결과

맞았습니다!!

댓글남기기