본문 바로가기

백준/골드

[백준 5557번] 1학년 (C++)

문제링크 : https://www.acmicpc.net/problem/5557

 

5557번: 1학년

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

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 987654321;

int N;
int arr[101];
ll dp [101][21]; //i번째 숫자까지의 조합으로 j를 만드는 경우
int main()
{
    ios_base::sync_with_stdio(0); 
	cin.tie(0);

    cin >> N;
    for(int i=0; i<N; i++)
    {
        cin >> arr[i];
    }

    dp[0][arr[0]] = 1; //초기화 (가장 처음 수는 무조건 들어감)

    for(int i=1; i<N-1; i++)
    {
        for(int j=0; j<21; j++)
        {
            if(!dp[i-1][j]) continue; //직전값이 없으면 패스
            if(j+arr[i]<21) dp[i][j+arr[i]] += dp[i-1][j]; //20이하인가?
            if(j-arr[i]>-1) dp[i][j-arr[i]] += dp[i-1][j]; //0이상인가?
        }
    }

    cout << dp[N-2][arr[N-1]];
    return 0;
}

처음에 문제를 잘못 이해하여 다소 헤맸던 dp 문제이다.

먼저 dp[i][j]은 i번째 숫자까지의 조합으로 j를 만드는 경우이다.

가장 처음 수는 무조건 들어가기에 dp[i][arr[i]]=1로 초기화를 하고 시작한다.

 

이후 이중 반복문을 돌리는데 i 반복문에서 맨 끝 숫자는 탐색을 할 필요가 없는 수이기에 N-1까지 탐색을 한다

이중반복문 안쪽에서 dp[i-1][j]의 유무를 판별하고 직전값이 있다면 이어서 탐색을 해주고 없다면 패스한다.

해당 j에 대해 arr[i]와 더해서 20이하인지 판별하고 20이하가 맞다면 dp[i][j+arr[i]]에 직전 dp값을 더해준다.

이어서 해당 j에 대해 arr[i]를 빼서 0이상인지 판별하고 0이상이 맞다면 dp[i][j-arr[i]]에 직전 dp값을 더해준다.

 

그리고 출력시에 dp[N-2][arr[N-1]]을 출력하는데 이는 위 반복문에서 i<N-1까지 탐색을 했기에 i=N-2이고,

arr[N-1]이 우리가 만들고자 하는 수(j)이기 때문이다.

'백준 > 골드' 카테고리의 다른 글

[백준 2631번] 줄세우기 (C++)  (0) 2023.10.19
[백준 1915번] 가장 큰 정사각형 (C++)  (0) 2023.10.18
[백준 2011번] 암호코드 (C++)  (0) 2023.10.16
[백준 2225번] 합분해 (C++)  (0) 2023.10.15
[백준 2294번] 동전 2 (C++)  (0) 2023.10.14