본문 바로가기
코딩 테스트/백준

2293 동전1

by 위그든씨 2025. 1. 6.

문제

n가지 종류의 동전이 있다. 각각의 동전이 나타내는 가치는 다르다. 이 동전을 적당히 사용해서, 그 가치의 합이 k원이 되도록 하고 싶다. 그 경우의 수를 구하시오. 각각의 동전은 몇 개라도 사용할 수 있다.

사용한 동전의 구성이 같은데, 순서만 다른 것은 같은 경우이다.

입력

첫째 줄에 n, k가 주어진다. (1 ≤ n ≤ 100, 1 ≤ k ≤ 10,000) 다음 n개의 줄에는 각각의 동전의 가치가 주어진다. 동전의 가치는 100,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 경우의 수를 출력한다. 경우의 수는 231보다 작다.

====

문제 분석

기존의 동전을 조합해서 k원을 만드는 경우의 수를 구하는 문제에서는 점화식 dp[i] = dp[i]+dp[i-coin]를 통하면 구할 수 있었다.

해당 문제에서 생기는 특이점은 동일한 숫자 조합은 같은 경우의 수로 봐서 배제해야한다는 것이다. 이 특이점을 해결하기 위해선 기존 점화식과 더불어 규칙을 만들면 됐다.

1,2,5 동전이 있다면 

1 -> (1)

2 -> (1,1) (2)

3->(1,1,1)(1,2)

4=> (1,1,1,1)(1,1,2)(2,2)

5=>(1,1,1,1)(1,1,1,2)(1,2,2)(5)

위에서 보았듯 숫자 조합을 오름차순으로으로만 만들면 되는 것이다.

하지만 이것을 위해 숫자들의 조합을 일일히 할 필요 없이 동전을 오름차순으로 정렬한 뒤 첫번째 동전으로만 만들 수 있는 최대한의 금액 조합을 만들고, 그 뒤 동전부터도 최대한의 금액 조합에 현재의 동전을 넣어주면 된다.

예를 들어, 동전 1원만으로 4원을 만들 수 있느 경우는 1,1,1,1 이다

이후 동전 2원까지 합세하여 만드는 경우는 4원-2원 = 2원의 조합에 2원을 추가해주면 된다는 것이다. --> (1,1,2) (2,2)

이것을 점화식으로 만들면 

dp[currentCoin] += dp[currentCoin - coin];

동전 첫 순서부터 금액 1~k원까지 반복문을 만든다.

for (let i = 0; i < n; i++) {
        const coin = coins[i];
        for (let currentCoin = 1; currentCoin <= k; currentCoin++) {
            if (currentCoin - coin < 0) continue;
            else {
                dp[currentCoin] += dp[currentCoin - coin];
            }
        }
}

정답코드

자바스크립트 정답 코드는 아래와 같은데 문제 이슈를 보니 node.js로 제출하면 뭔 짓을 하든 메모리 초과가 뜬다고 한다.

그래서 파이썬으로 변행해서 제출했더니 정답 됨

const main = (n, k, coins) => {
    const dp = Array.from({ length: k + 1 }).fill(0);
    dp[0] = 1;
    coins.sort((a, b) => a - b);

    for (let i = 0; i < n; i++) {
        const coin = coins[i];
        for (let currentCoin = 1; currentCoin <= k; currentCoin++) {
            if (currentCoin - coin < 0) continue;
            else {
                dp[currentCoin] += dp[currentCoin - coin];
            }
        }
    }
    console.log(dp);
};
const input = require('fs')
    .readFileSync(process.platform === 'linux' ? '/dev/stdin' : './input.txt')
    .toString()
    .trim()
    .split('\n');

const [n, k] = input[0].split(' ').map((v) => +v);
const coin = [];
for (let i = 1; i < n + 1; i++) {
    coin.push(+input[i]);
}

main(n, k, coin);

 

def main(n, k, coins):
    dp = [0] * (k + 1)
    dp[0] = 1
    coins.sort()

    for coin in coins:
        for current_coin in range(1, k + 1):
            if current_coin - coin >= 0:
                dp[current_coin] += dp[current_coin - coin]

    print(dp[k])

if __name__ == "__main__":
    import sys
    input = sys.stdin.read
    data = input().strip().split("\n")

    n, k = map(int, data[0].split())
    coins = list(map(int, data[1:]))

    main(n, k, coins)

'코딩 테스트 > 백준' 카테고리의 다른 글

11052 카드 구매하기, 16194 카드 구매하기 2  (0) 2025.01.08
2281 데스노트 (자바스크립트)  (0) 2025.01.07
16932 모양 만들기  (0) 2025.01.04
13398 연속합2  (0) 2025.01.04
5557번 1학년 (자바스크립트)  (0) 2025.01.04