본문 바로가기
SWE/코테

[성실코딩 32일차] 백준 #11047 동전 0 / 그리디 **

by S나라라2 2018. 12. 10.
반응형

기말고사 준비로 Knapsack 문제만 풀고 싶었는데,,, 

이건 그리드알고리즘을 이용해서 푸는 문제라고 한다. 

그 이유가 되는 단서는 문제에서,

(1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수) 

이러한 조건을 줬기때문에 그리디 알고리즘을 이용해서 푼다고 한다. 

막 나누고 어떻게 하던데,, 기말 끝나고 시도해봐야겠다.


나는 Knapsack으로 풀어서 모두 메모리 초과가 났다 ㅠㅠ


1풀이법. 재귀적으로 

#include < stdio.h >
#include < stdlib.h > // malloc
#include < string.h > // memset

#define INF 987654321

int n, k; // 동전의 개수n, 금액k

int coins[11];

// _k : 채워야하는 금액
// 2차원 배열 사용 안하고 재귀적으로 구하기
int getMinimumCoinCnt(int _k) { 
	
	if (_k==0) { // 탈출조건
		return 0;
	}
	
	int minimum = INF;
	for (int i = 0; i < n; i++) {  // n: 동전 개수
		int new_value = INF;
		if (coins[i] <= _k) {
			int temp = getMinimumCoinCnt(_k - coins[i]);
			if (temp != -1) { // -1이 아니라는 것은
							  // 동전 i를 사용해서 금액 _k를 만들 수 있다.
				new_value = temp + 1;
				if (minimum > new_value) { // minimum update
					minimum = new_value;
				}
			}
		}
	}
	if (minimum == INF) {  // 불가능한 경우 
							// 내가 가진 코인들을 이용해서 금액 _k를 만들 수 없음.
		return -1;
	}
	else {
		return minimum;
	}
}

int main(void) {

	// 입력
	scanf("%d %d",&n,&k);
	for (int i = 0; i < n; i++) {
		scanf("%d", &coins[i]);
	}
	
	printf("%d\n", getMinimumCoinCnt(k));

	return 0;
}


1-1 풀이법. 재귀적으로 + k금액을 이룰수 있는 경우, 거기서 반복문을 멈춘다. 

-> 왜 다른 코인을 사용한 경우를 확인해주지 않아도 되는지 모르겠음. 

어차피 문제에서 코인을 줄 때 오름차순으로 주기 때문인가?

#include < stdio.h >
#include < stdlib.h > // malloc
#include < string.h > // memset

#define INF 987654321

int n, k; // 동전의 개수n, 금액k

int coins[11];

// _k : 채워야하는 금액
// 2차원 배열 사용 안하고 재귀적으로 구하기
int getMinimumCoinCnt(int _k) { 
	
	if (_k==0) { // 탈출조건
		return 0;
	}
	
	int minimum = INF;
	for (int i = n-1; i > -1; i--) {  // n: 동전 개수
		int new_value = INF;
		if (coins[i] <= _k) {
			int temp = getMinimumCoinCnt(_k - coins[i]);
			if (temp != -1) { // -1이 아니라는 것은
							  // 동전 i를 사용해서 금액 _k를 만들 수 있다.
				new_value = temp + 1;
				if (minimum > new_value) { // minimum update
					minimum = new_value;
					break;
				}
			}
		}
	}
	if (minimum == INF) {  // 불가능한 경우 
							// 내가 가진 코인들을 이용해서 금액 _k를 만들 수 없음.
		return -1;
	}
	else {
		return minimum;
	}
}

int main(void) {

	// 입력
	scanf("%d %d",&n,&k);
	for (int i = 0; i < n; i++) {
		scanf("%d", &coins[i]);
	}
	
	printf("%d\n", getMinimumCoinCnt(k));

	return 0;
}


2풀이법.  1차원 array를 만들어서 DP Table을 채워가며 

#include < stdio.h >
#include < stdlib.h > // malloc
#include < string.h > // memset

#define INF 987654321

int n, k; // 동전의 개수n, 금액k

int coins[11];
int DP[100000001] = { 0, };

// _k : 채워야하는 금액
// 2차원 배열 사용 안하고 재귀적으로 구하기
int getMinimumCoinCnt(int _k) { 
	
	int minimum = INF;
	for (int i = 0; i < n; i++) {  // n: 동전 개수
		int new_value = INF;
		if (coins[i] <= _k && DP[_k-coins[i]]!=-1) { // -1이 아니라는 것은
													  // 동전 i를 사용해서 금액 _k를 만들 수 있다.	
			new_value = DP[_k - coins[i]] + 1;
			if (minimum > new_value) { // minimum update
				minimum = new_value;
			}
		}
	}
	if (minimum == INF) {  // 불가능한 경우 
							// 내가 가진 코인들을 이용해서 금액 _k를 만들 수 없음.
		return -1;
	}
	else {
		return minimum;
	}
}

int main(void) {

	// 입력
	scanf("%d %d",&n,&k);
	for (int i = 0; i < n; i++) {
		scanf("%d", &coins[i]);
	}
	
	// DP Table채우기
	DP[0] = 0;
	for (int i = 1; i <= k; i++) {
		DP[i] = getMinimumCoinCnt(i);
	}
	printf("%d\n", DP[k]);

	return 0;
}


2-1 풀이법.  1차원 array + k금액을 이룰 수 있는 경우, 거기서 반복문을 멈춘다. (모든 코인을 확인해보지 않아도 된다.)

이것도 1-1풀이법과 같은 이유로 왜 가능한지 의문이다.

#include < stdio.h >
#include < stdlib.h > // malloc
#include < string.h > // memset

#define INF 987654321

int n, k; // 동전의 개수n, 금액k

int coins[11];
int DP[100000001] = { 0, };

// _k : 채워야하는 금액
// 2차원 배열 사용 안하고 재귀적으로 구하기
int getMinimumCoinCnt(int _k) { 
	
	int minimum = INF;
	for (int i = n-1; i > -1; i--) {  // n: 동전 개수
		int new_value = INF;
		if (coins[i] <= _k && DP[_k-coins[i]]!=-1) { // -1이 아니라는 것은
													  // 동전 i를 사용해서 금액 _k를 만들 수 있다.	
			new_value = DP[_k - coins[i]] + 1;
			if (minimum > new_value) { // minimum update
				minimum = new_value;
				break;
			}
		}
	}
	if (minimum == INF) {  // 불가능한 경우 
							// 내가 가진 코인들을 이용해서 금액 _k를 만들 수 없음.
		return -1;
	}
	else {
		return minimum;
	}
}

int main(void) {

	// 입력
	scanf("%d %d",&n,&k);
	for (int i = 0; i < n; i++) {
		scanf("%d", &coins[i]);
	}
	
	// DP Table채우기
	DP[0] = 0;
	for (int i = 1; i <= k; i++) {
		DP[i] = getMinimumCoinCnt(i);
	}
	printf("%d\n", DP[k]);

	return 0;
}



 => 재귀적으로 푸는 건 함수 타고 들어가면서 heap 메모리에서 stackoverflow 문제가 발생했고

DP Table 채워가며 푸는 건 전역변수로 1억개를 할당해서 data 메모리에서 메모리 초과가 난 것 같다.'


=> 기말 끝나고 그리디로 다시 풀어봐야겠다.

반응형