티스토리 뷰

Algorithm/동적프로그래밍

백준 9084 동전

선비마을송 2018. 9. 20. 20:21

이 문제는 동적 프로그래밍을 알아야 풀 수 있는 문제입니다. 

동적 프로그래밍은 표로 그려 머리로 이해를 해야 코드를 이해하실 수 있습니다. 

동적 프로그래밍을 잘 모르신다면, 개념을 익히시고 문제를 푸셔야 합니다.

코드를 보기 전, 설명을 보고 직접 표를 그려보시는 것을 권장합니다. 


설명하기 쉽게 10원을 3개의 2원, 3원, 5원을 이용해 몇 가지로 나타낼 수 있는지 가정하겠습니다. 


먼저 저에게 2원짜리만 있다고 가정합니다. 2원짜리만 있을 때 1~10원을 몇 가지의 방법으로 나타낼 수 있는지 표로 그려봅니다. 

2원짜리로 2원은 1가지, 4원은 2+2로 1가지, 6원은 2+2+2로 1가지..로 나타낼 수 있습니다. 이를 10원까지 생각해 표로 그려봅니다.

 

 

 1원

2원 

3원 

4원 

5원 

6원 

7원 

8원 

9원 

10원 

2원 

0

 3원

 

 

 

 

 

 

 

 

 

 

 5원

 

 

 

 

 

 

 

 

 

 



다음으로, 3원짜리 동전이 저에게 있다고 가정합니다. 

3원짜리 동전으로 3원은 1가지지만 6원은 2+2+2와 3+3 2가지의 경우가 존재합니다. 

여기서 동적 프로그래밍의 개념이 나옵니다. 

이전의 경우를 저장해놓고, 현재의 경우와 이전의 경우를 합해 나가면서 경우의 수를 계산합니다.


즉, 6원을 만드는 경우의 수를 계산할 때, 2원짜리로 6원을 만들 수 있는 경우의 수와 3원짜리로 6원을 만들 수 있는 경우의 수를 합해야 한다는 의미입니다. 


하나 더 고려해야 할 점이 있습니다. 3원으로 경우의 수를 계산하는데 1원과 2원의 경우를 계산할 필요가 있을까요?

어차피 제가 가지고 있는 동전은 3원이기 때문에 1원과 2원은 생각할 필요도 없게 되는 것입니다. 


표로 그려보겠습니다.


 

 1원

2원 

3원

4원 

5원 

6원 

7원

8원 

9원 

10원 

2원 

3원 

1

 5원

 

 

 

 

 

 

 

 

 

 


마지막으로 저에게 5원의 동전이 있다고 가정하고 표를 그려보겠습니다.


 

 1원

2원 

3원 

4원 

5원 

6원 

7원 

8원 

9원 

10원 

2원 

3원 

1

5원 

x


이제 개념을 알았으니 코드로 구현해 보겠습니다. 

배열의 인덱스에 주의해 주세요. 혼동이 많이 올 수 있습니다.

동전의 가짓수를 n, 2원, 3원, 5원을 담을 배열을 coin, 표를 담을 동적 배열을 d라고 선언하겠습니다.


d[10]이 아니라 d[11]로 선언한 이유는, 좀 더 직관적이기 때문입니다. 0원부터 9원이 아닌, 1원부터 10원까지로 생각하는 것이 더 편하기에 저는 11로 선언했습니다. 


동적 프로그래밍을 사용하기 위해서, 초기값 d[0]=1로 주어야 합니다.


i는 첫 번째 2원의 경우, 두 번째 3원의 경우, 세 번째 5원의 경우를 의미합니다. 

j는 2원으로 1~10원을 채우는 경우의 수, 3원으로 1~10원을 채우는 경우의 수, 5원으로 1~10원을 채우는 경우의 수를 의미합니다.  


최종적으로 저희가 원하는 4는 d[10]에 저장됩니다. 코드는 다음과 같습니다. 

#include <iostream>

using namespace std;

int main()
{
	//최대 몇 개?
	int n = 3;
	int coin[4] = { 0 };
	int d[11] = { 0 };
	coin[1] = 2;
	coin[2] = 3;
	coin[3] = 5;

	d[0] = 1;

	for (int i = 1;i <= n;i++) {
		for (int j = coin[i];j <= 10;j++) {
			d[j] += d[j - coin[i]];
		}
	}

	cout << d[10];
}


백준 문제 9084번 동전에 위에서 설명한 내용을 생각하며 풀어봅니다. 배열의 인덱스만 주의하시면 큰 어려움 없이 해결하실 수 있습니다. 

#include <iostream>

using namespace std;

int main()
{
	//테스트케이스 T
	int T;
	cin >> T;
	int coin[21] = { 0 };

	for (int t = 0;t < T;t++) {
		//동전의 가짓수 N
		int N;
		//만들어야 할 금액 M
		int M;
		cin >> N;

		for (int n = 1;n <= N;n++) {
			cin >> coin[n];
		}
		cin >> M;

		int d[10001] = { 0 };
		d[0] = 1;

		for (int i = 1;i <= N;i++) {
			for (int j = coin[i];j <= M;j++) {
				d[j] += d[j - coin[i]];
			}
		}
		cout << d[M] << endl;
	}

	return 0;
}



' Algorithm > 동적프로그래밍' 카테고리의 다른 글

백준 1149 RGB거리  (0) 2018.09.28
백준 9095 1, 2, 3 더하기  (0) 2018.09.27
백준 2294 동전2  (0) 2018.09.21
백준 3908 서로 다른 소수의 합  (0) 2018.09.21
백준 2293 동전1  (0) 2018.09.20
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함