https://www.acmicpc.net/problem/5557
문제
상근이가 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 이하이다.
문제 풀이
dp 문제.
각 중간 단계마다 0부터 20까지 만들 수 있는 경우의 수를 2차원 dp 배열에 저장한다. 행은 맨 마지막 숫자가 나오도록 등식의 맨 마지막에 =가 붙어야 하므로 N-1개 필요하고, 열은 0부터 20까지 만들 수 있는 경우의 수를 저장하기 위해 21개 필요하므로 크기는 dp[N-1][21]가 된다.
각 단계마다 숫자 j에 이번 단계의 숫자 arr[i]를 더해 l을 만들었다고 하면, l를 만드는 경우의 수는 덧셈의 경우 한가지밖에 없으므로 j를 만드는 경우의 수와 같다. 마찬가지로 j에 arr[i]를 빼서 만든 m의 경우의 수는 빼는 경우 한가지밖에 없으므로 j를 만드는 경우의 수와 같다.
위의 설명을 이용해 반복문을 돌려 dp[i][j + arr[i]]와 dp[i][j-arr[i]]에 각각 dp[i][j]를 더해 경우의 수를 구한다. N-2번째 인덱스까지 반복한 뒤 dp[N-2][arr[N-1]]를 출력해주면 된다.
아래는 코드.
#include <iostream>
#include <utility>
using namespace std;
int main()
{
cin.tie(NULL);
ios::sync_with_stdio(false);
int N;
cin >> N;
int* arr = new int[N];
long long** nums = new long long*[N];
for (int i = 0; i < N; i++)
{
cin >> arr[i];
nums[i] = new long long[21];
for (int j = 0; j < 21; j++)
{
nums[i][j] = 0;
}
}
nums[0][arr[0]]= 1;
for (int i = 1; i < N-1; i++)
{
for (int j = 0; j < 21; j++)
{
if (j + arr[i] >= 0 && j + arr[i] <= 20)
{
nums[i][j + arr[i]] += nums[i - 1][j];
}
if (j - arr[i] >= 0 && j - arr[i] <= 20)
{
nums[i][j - arr[i]] += nums[i - 1][j];
}
}
}
for (int i = 0; i < 21; i++)
{
nums[N - 1][i] = nums[N - 2][i];
}
cout << nums[N - 1][arr[N - 1]] << "\n";
return 0;
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준 11066] 파일 합치기 (C++) (0) | 2024.06.24 |
---|---|
[백준 10610] 30 (C++) (0) | 2024.06.23 |
[백준 1062] 가르침 (C++) (0) | 2024.06.20 |
[백준 1939] 중량제한 (C++) (0) | 2024.06.19 |
[백준 1269] 대칭 차집합 (C++) (0) | 2024.06.18 |