프로그래머스: 거스름돈⭐⭐⭐(실패)

업데이트:     Updated:

카테고리:

태그: , , ,

난이도 ⭐⭐⭐
유형 : DP

🧐 문제

문제 설명

Finn은 편의점에서 야간 아르바이트를 하고 있습니다. 야간에 손님이 너무 없어 심심한 Finn은 손님들께 거스름돈을 n 원을 줄 때 방법의 경우의 수를 구하기로 하였습니다.

예를 들어서 손님께 5원을 거슬러 줘야 하고 1원, 2원, 5원이 있다면 다음과 같이 4가지 방법으로 5원을 거슬러 줄 수 있습니다.

  • 1원을 5개 사용해서 거슬러 준다.
  • 1원을 3개 사용하고, 2원을 1개 사용해서 거슬러 준다.
  • 1원을 1개 사용하고, 2원을 2개 사용해서 거슬러 준다.
  • 5원을 1개 사용해서 거슬러 준다.

거슬러 줘야 하는 금액 n과 Finn이 현재 보유하고 있는 돈의 종류 money가 매개변수로 주어질 때, Finn이 n 원을 거슬러 줄 방법의 수를 return 하도록 solution 함수를 완성해 주세요.

제한 사항

  • n은 100,000 이하의 자연수입니다.
  • 화폐 단위는 100종류 이하입니다.
  • 모든 화폐는 무한하게 있다고 가정합니다.
  • 정답이 커질 수 있으니, 1,000,000,007로 나눈 나머지를 return 해주세요.

입출력 예

n money result
5 [1,2,5] 4

입출력 예 설명

입출력 예 #1
문제의 예시와 같습니다.


✏️ 나의 풀이(실패)

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

unsigned long long cnt=0;

void dfs(vector<int> money, int ind, int total) {
  if(money.size() <= ind) return;
  if(total == 0) {
    cnt++;
    return;
  }

  if(total >= money[ind])
    dfs(money, ind, total-money[ind]);
  dfs(money, ind+1, total);
}

int solution(int n, vector<int> money) {   
    sort(money.begin(), money.end(), greater<>());
    dfs(money, 0, n);

    return cnt%1000000007;
}

dfs를 사용하여 순회해보려 했지만 효율성 테스트에서 탈락하였다.

이유는 중복되는 계산이 여러번 존재하기에 수가 커질수록 감당할 수 없어졌기 때문이다.

✔️ 다른 사람의 풀이(C++로 변환)

#include <iostream>
#include <vector>

using namespace std;

int solution(int n, vector<int> money) {   
    vector<int> dp(n+1);
    dp[0] = 1;
    
    for(int m : money)
        for(int i=m; i<n+1; i++)
            dp[i] += dp[i-m];

    return dp[n]%1000000007;
}

🧐 분석

|거스름돈|1|2|3|4|5|6|7|8|9| |—|—|—|—|—|—|—|—|—|—| |1원|1|1|1|1|1|1|1|1|1| |2원|1|1+1|1+1|1+2|1+2|1+3|1+3|1+4|1+4| |5원|1|1+1|1+1|1+2|1+2+1|1+3+1|1+3+2|1+4+2|1+4+3| |경우의 수|1|2|2|3|4|5|6|7|8|

기본적으로 화폐의 종류는 오름차순으로 정렬되어 있다.

이후 새로운 화폐가 추가될때마다, 기존의 배열을 재사용하여 경우의 수를 계산하고 있다.

🪶 후기

오랜만에 돌아와 문제를 풀며, DP쪽이 매우 부족하다는 것을 다시 한번 알게 되었다. 기본적인 문제였지만 제대로 풀지 못해서 매우 아쉬웠다.

Programmers 카테고리 내 다른 글 보러가기

댓글남기기