DP의 대표적인 동전문제 관련질문입니다.
글쓴이: canuyes / 작성시간: 일, 2013/07/28 - 10:00오후
우선 문제는 아래와 같습니다.
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문의 의미를 알려주세요.
겸손한 마음으로 답변 기다립니다.
Forums:
// d[X] : X원을 만드는 경우의
예를 들어서
1원짜리와 5원짜리를 가지고 10원을 만든다면
이런 식인 거죠.
물론 이건 코드를 보면서 역으로 생각한 거고... 대뜸 풀라고 하면 금방 떠올릴 수 있었을지는 자신이 없네요 ^^;
좋은 하루 되세요!
댓글 달기