1. 문제

1) 문제 링크

    : www.acmicpc.net/problem/5557

 

5557번: 1학년

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

www.acmicpc.net

 

2) 설명

숫자 배열이 있으면 마지막 숫자 전에 = 기호를, 나머지 각 숫자 사이에 +나 - 기호를 넣어서 등식을 성립하게 만들 수 있는 경우의 수를 구하면 된다.

단 계산 과정 중(왼쪽부터 계산하는 방식) 음수나 20을 초과하는 수가 나와서는 안 된다.

2. 풀이

1) 알고리즘

    : DP

 

2) 풀이 설명

 

0 ~ N-2 까지의 입력받은 숫자를 더하고 빼서 N-1번째에 입력받은 숫자를 만들어내면 된다.

즉 nums[0], nums[1], ... ,nums[N-2] 를 더하고 빼서 nums[N-1]을 만들면 된다.

 

그래서 i번째 이전 숫자들을 더하고 빼서 0부터 20까지 각각의 숫자를 만들 수 있는 경우의 수를 저장하는 DP 배열을 만들었다.

ex) DP[10][4] 에는 nums[0], nums[1], nums[2], nums[3], nums[4] 를 더하고 빼서 10을 만들 수 있는 경우의 수가 들어있다.

그러므로 DP배열은 21행( 0 ~ 20 ), N-1열( 0 ~ N-2 )을 가지게 된다.

초기값은 첫번째 DP[nums[0]][0] = 1로 주어진다.(첫 수(nums[0])으로 nums[0]을 만드는 경우의 수는 하나이기 때문에)

또한 점화식은 아래와 같이 세워진다.

 

DP[x][i] = DP[x][i] + DP[x-nums[i]] (단 x-nums[i] >= 0)

DP[x][i] = DP[x][i] + DP[x+nums[i]] (단 x+nums[i] <= 20)

 

이렇게 N-2열까지 돌리고나면 DP[nums[N-1]][N-2] 값이 답이 된다.(nums[0], nums[1], ... , nums[N-2]를 사용해서 nums[N-1]을 만드는 경우의 수)

 

3. 코드

더보기
/*
	1학년
	DP
*/
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	const int maxSum = 20;
	int N;
	cin >> N;

	vector<int> nums(N);

	for(int i=0;i<N;i++)
		cin >> nums[i];

	vector<vector<long long>> DP(21, vector<long long>(N, 0));
	
	DP[nums[0]][0] = 1;

	for(int i=1;i<N-1;i++){
		for(int j=0;j<=maxSum;j++){
			if(j-nums[i] >= 0)
				DP[j][i] += DP[j-nums[i]][i-1];
			if(j+nums[i] <= maxSum)
				DP[j][i] += DP[j+nums[i]][i-1];
		}
	}

	cout << DP[nums[N-1]][N-2] << "\n";

	return 0;
}

 

4. 느낀점

 

 - 값의 범위 잘 생각하기(long long 줘야하는데 int로 선언해서 틀렸었다.)

 - 가독성 높은 점화식 세우기

'알고리즘 > 백준' 카테고리의 다른 글

[백준/15312] 이름 궁합  (1) 2020.10.18
[백준/17070] 파이프 옮기기 1  (0) 2020.10.18
[백준/1261] 알고스팟  (0) 2020.10.16
[백준/9655] 돌 게임  (0) 2020.10.16
[백준/7569] 토마토  (0) 2020.10.10

+ Recent posts