본문 바로가기
공부/이것이 코딩테스트다

그리디 알고리즘 - 큰 수의 법칙

by 박영귤 2023. 1. 1.

< 큰 수의 법칙 > 

난이도 : 하

[문제]

동빈이의 큰 수의 법칙은 다양한 수로 이루어진 배열이 있을 때 주어진 수들을 M번 더하여 가장 큰 수를 만드는 방법이다. 단, 배열의 특정한 인덱스에 해당하는 수가 연속해서 K번을 초과하여 더해질 수 없는 것이 이 법칙의 특징이다.

예를 들어 순서대로 2, 4, 5, 4, 6으로 이루어진 배열이 있을 때, M이 8이고 K가 3이라고 가정하자.

이 경우 특정한 인덱스의 수가 연속해서 세 번까지만 더해질 수 있으므로 큰 수의 법칙에 따른 결과는 6 + 6 + 6 + 5 + 6 + 6 + 6 + 5인 46이 된다. 단, 서로 다른 인덱스에 해당하는 수가 같은 경우에도 서로 다른 것으로 간주한다.

예를 들어 순서대로 3, 4, 3, 4, 3으로 이루어진 배열이 있을 때 M이 7이고 K가 2라고 가정하자. 이 경우 두 번째 원소에 해당하는 4와 네 번째 원소에 해당하는 4를 번갈아 두 번씩 더하는 것이 가능하다.

결과적으로 4 + 4 + 4 + 4 + 4 + 4 + 4 인 28이 도출된다.
배열의 크기 N, 숫자가 더해지는 횟수 M, 그리고 K가 주어질 때 동빈이의 큰 수의 법칙에 따른 결과를 출력하시오.

 

[입력 조건]

  • 첫째 줄에 N(2 <= N <= 1000), M(1 <= M <= 10000), K(1 <= K <= 10000)의 자연수가 주어지며 각자 연수는 공백으로 구분한다.
  • 둘째 줄에 N개의 자연수가 주어진다. 각 자연수는 공백으로 구분한다.
    단, 각각의 자연수는 1 이상 10000 이하의 수로 주어진다.
    입력으로 주어지는 K는 항상 M보다 작거나 같다.

[출력 조건]

  • 첫째 줄에 동빈이의 큰 수의 법칙에 따라 더해진 답을 출력한다.

[입력 예시]                                                                        [출력 예시]

5 8 3                                                                                        46
2 4 5 4 6


영규's 코드

N, M, K = map(int, input().split())
nums = list(map(int, input().split()))

nums.sort()
sum = 0
# 연속 횟수 계산
continuous_cnt = 0 
for i in range(M):
    # K번 연속 계산 했으면
    if continuous_cnt == K:
        continuous_cnt = 0
        sum += nums[-2]
    # 아직 K번 계산 안 했으면
    else :
        continuous_cnt += 1
        sum += nums[-1]
print(sum)

단순무식하게 반복하여 더하는 알고리즘이다. 이 다음은 조금 더 똑똑한 코드를 작성해보았다.

 

영규's 코드

N, M, K = map(int, input().split())
nums = list(map(int, input().split()))
nums.sort()

cnt_idx2 = M // (K + 1) # 두 번째로 큰 수는 M // (K + 1)번 더해짐. 
sum = nums[-2] * cnt_idx2
sum += nums[-1] * (M - cnt_idx2) # 그 외는 모두 첫 번째로 큰 수.

print(sum)

두 번째로 큰 수와 제일 큰 수가 몇 번씩 등장하는지를 계산하여 푸는 알고리즘이다.