DP의 대표적인 동전문제 관련질문입니다.

canuyes의 이미지

우선 문제는 아래와 같습니다.

n가지 종류의 동전이 있고 그 가치는 가각 다르다.
이동전들을 적당히 사용하여 가치의 합이 k원이 되도록 하려한다.
그 경우의 수를 구하시오. ( 각각의 동전은 무제한으로 사용가능)

저는 전형적인 DP문제라고 생각하고 다음과 같이 작성하였습니다.

#include<iostream>
#include<cstring>
 
using namespace std;
 
int N,K,COIN[100],CACHE[101][10001];
 
int mkCACHE(int x,int p){
    int i,&ret=CACHE[x][p];
    if(ret==-1){
                if(p==0){ret=1;}
                else if(x==0){ret=0;}
                else{
                     ret=0;
                     for(i=0;p-COIN[x-1]*i>=0;i++){ret+=mkCACHE(x-1,p-COIN[x-1]*i);}          
    }}
    return ret;
}
 
int main(void){
    int i;
    cin>>N>>K;
    for(i=0;i<=N;i++){memset(CACHE[i],-1,sizeof(int)*(K+1));}
    for(i=0;i<N;i++){cin>>COIN[i];}
    cout<<mkCACHE(N,K)<<endl;
    return 0;
}

하지만 문제의 메모리 제한이 4mb였기 때문에 캐시배열로 인해 메모리 초과를 경험하였습니다.
그래서 재귀를 사용하지 않는 형식으로 아래와 같은 반복문코드(배열 역시 재활용하는)을 작성하여서 답을 얻었습니다.

#include<iostream>
#include<cstring>
using namespace std;
int N,K,COIN[100],CACHE[2][10001];
int mkCACHE(void){
        int i,j,k;
        for(i=0;i<=N;i++){
                for(j=0;j<=K;j++){
                        if(j==0){CACHE[0][j]=1;CACHE[1][j]=1;}
                        else if(i==0){CACHE[0][j]=0;}
                        else{
                                CACHE[1][j]=0;
                                for(k=0;j-COIN[i-1]*k>=0;k++){CACHE[1][j]+=CACHE[0][j-COIN[i-1]*k];}
                }}
                if(i!=0){memcpy(CACHE[0],CACHE[1],sizeof(int)*(K+1));}
        }
        if(N==0){return CACHE[0][K];}
        return CACHE[1][K];
}
int main(void){
        cin>>N>>K;
        for(int i=0;i<N;i++){cin>>COIN[i];}
        cout<<mkCACHE()<<endl;
        return 0;
}

온라인 저지이다 보니 다른 분들의 답안을 볼 수 있었습니다.
하지만 그 코드를 이해할 수 없었습니다.
그 코드에 관해 질문올립니다.
그 코드는 아래와 같습니다.

#include <cstdio>
#include <algorithm>
using namespace std;
int main(){
    int i,j,n,k,a[101]={0,};
    int d[10001]={0,};
 
    scanf("%d %d",&n,&k);
    if(n<1 || n>100 || k<1 || k>10000)  return 0;
    for(i=0;i<n;i++) scanf("%d",&a[i]);
    d[0]=1;
    sort(a,a+n);
    for(i=0;i<n;i++){
        for(j=a[i];j<=k;j++){
            d[j]+=d[j-a[i]];
        }
    }
    printf("%d\n",d[k]);
    return 0;
}

아무래도 중요한부분은 이중for문 부분인 것 같습니다.
저 이중 for문의 의미를 알려주세요.
겸손한 마음으로 답변 기다립니다.

raymundo의 이미지

// d[X] : X원을 만드는 경우의 수
 
d[0] = 1;       // 0원을 만드는 경우의 수는 1가지.
 
// 동전이 1가지만 있을때 (가치는 a[0]원), N*a[0]원을 만드는 경우는 1가지이고, 나머지 액수의 경우는 0가지
// 이것이 i=0 일때의 for 루프가 하는 일
d[ a[i]의 배수 ] = 1;
 
// i=1 부터는
a[i]원짜리 동전이 추가되었을 때
j 원을 만드는 경우의 수 d[j] =
                                a[i]원짜리 동전이 추가되기 전에 계산한 d[j]
                                +
                                a[i]원짜리 동전이 추가된 후에 j-a[i]원을 만드는 경우의 수 (여기에 a[i]원 동전 하나를 더하면 j원이 됨)

예를 들어서
1원짜리와 5원짜리를 가지고 10원을 만든다면

액수:          0  1  2  3  4  5  6  7  8  9  10
1원짜리사용:   1  1  1  1  1  1  1  1  1  1   1
5원짜리추가:                  1                  5원을 만들때 5원짜리를 쓰는 경우가 추가
                                 1               6원도 마찬가지
                                    1            7원도 마찬가지
                                       ...
                                              2  5원을 만드는 경우의 수 2가지(1*5, 5*1)에서 5원짜리를 하나 추가해서 10원을 만드는 2가지
 
d[10] = 1 + 2 = 3

이런 식인 거죠.

물론 이건 코드를 보면서 역으로 생각한 거고... 대뜸 풀라고 하면 금방 떠올릴 수 있었을지는 자신이 없네요 ^^;

좋은 하루 되세요!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.