말랑말랑한 개발자 이야기

[백준 5557번] 1학년 본문

알고리즘/백준

[백준 5557번] 1학년

말랑너구리 2021. 5. 18. 14:11

[백준 5557번] 1학년

www.acmicpc.net/problem/5557

 

5557번: 1학년

상근이가 1학년 때, 덧셈, 뺄셈을 매우 좋아했다. 상근이는 숫자가 줄 지어있는 것을 보기만 하면, 마지막 두 숫자 사이에 '='을 넣고, 나머지 숫자 사이에는 '+' 또는 '-'를 넣어 등식을 만들며 놀

www.acmicpc.net

 

 문제

 상근이가 1학년 때, 덧셈, 뺄셈을 매우 좋아했다. 상근이는 숫자가 줄 지어있는 것을 보기만 하면, 마지막 두 숫자 사이에 '='을 넣고, 나머지 숫자 사이에는 '+' 또는 '-'를 넣어 등식을 만들며 놀고 있다. 예를 들어, "8 3 2 4 8 7 2 4 0 8 8"에서 등식 "8+3-2-4+8-7-2-4-0+8=8"을 만들 수 있다.

 상근이는 올바른 등식을 만들려고 한다. 상근이는 아직 학교에서 음수를 배우지 않았고, 20을 넘는 수는 모른다. 따라서, 왼쪽부터 계산할 때, 중간에 나오는 수가 모두 0 이상 20 이하이어야 한다. 예를 들어, "8+3+2-4-8-7+2+4+0+8=8"은 올바른 등식이지만, 8+3+2-4-8-7이 음수이기 때문에, 상근이가 만들 수 없는 등식이다.

 숫자가 주어졌을 때, 상근이가 만들 수 있는 올바른 등식의 수를 구하는 프로그램을 작성하시오.

 

 입력

 첫째 줄에 숫자의 개수 N이 주어진다. (3 ≤ N ≤ 100) 둘째 줄에는 0 이상 9 이하의 정수 N개가 공백으로 구분해 주어진다.

 

 출력

 첫째 줄에 상근이가 만들 수 있는 올바른 등식의 개수를 출력한다. 이 값은 263-1 이하이다.

 

 

 풀이

#include <iostream>
using namespace std;

int N, arr[101] = {0,};
long long memo[101][21];
long long go(int sum, int index){
	if(sum < 0 || sum > 20) return 0;
	if(memo[index][sum] != -1) return memo[index][sum];
	if(index == N-1){
		if(sum == arr[index]) memo[index][sum] = 1;
		else memo[index][sum] = 0;
		return memo[index][sum];
	}
	
	long long v = 0;
	v += go(sum + arr[index], index + 1);
	v += go(sum - arr[index], index + 1);
	memo[index][sum] = v;
	return memo[index][sum];

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	
	cin >> N;
	for(int i=0;i<N;i++) cin >> arr[i];
	for(int i=0;i<N;i++){
		for(int j=0;j<=20;j++){
			memo[i][j] = -1;
		}
	}
	cout << go(arr[0], 1);
}

 5/18일자 두번째 문제로 상당히 괜찮은 문제인 것 같다. 처음에는 단순 재귀로 접근했는데 시간 초과가 났다. 생각해보니 N이 100까지 가능하고 100회 동안 +, - 두가지 경우로 쪼개지니 O(2^100)으로 당연한 결과였다. 따라서 메모이제이션이라는 방법을 사용한다. DP의 일환으로 TOP-DOWN 방식의 DP이다. 나는 DP문제다 하면은 점화식을 이끌어내서 BOTTOM-UP 방식만을 생각했었는데 아니었다. 넓은 생각을 하게 해줘서 좋은 문제라고 생각했다.

 

 1. 재귀 형식은 유지하되 값을 저장해나가는 방식

 2. 저장된 값이 존재하면 이 후 재귀는 하지않고 저장된 값을 이용

 3. 음수나 20초과는 return 0

 4. 마지막 인덱스까지 도달 후 마지막 값과 같으면 1, 아니면 0

 

조건만 잘 생각해서 있는 그대로 짜주면 된다. 위 구조를 잘 기억해두면 다음 메모이제이션 문제를 풀 때 도움이 될 것같다.