본문 바로가기
코딩 테스트/백준

5557번 1학년 (자바스크립트)

by 위그든씨 2025. 1. 4.

상근이가 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 이하이다.

====

문제 분석

인덱스 처음부터 마지막 직전(n-1)까지 + - 를 사용해가면서 arr의 마지막 값을 만드는 경우의 수를 출력하는 방식이다.

이 때 계산으로 나온 숫자는 0이상 20이하라는 제한이 있지만, DFS나 BFS와 같은 완전 탐색으로 계산을 할 경우 최대 

2^100 의 연산이 일어 날 수 있어서 특정 규칙을 찾아야했다.

0~20이라는 조건이라는 특이점을 사용하여 각 인덱스별로 0부터 20을 만들 수 있는 경우의 수를 기록하는 것이다.

예를 들어 인덱스 0 이 8일 때, 인덱스 0으로 만들 수 있는 수는 8 1개이다.

인덱스 1이 3일 때, 만들 수 있는 수는 이전 인덱스 0까지 만들 수 있는 경우의 수들로 조합을 만드는 것이다.

인덱스 0까지 만들 수 있는 것은 8 하나였다.

그렇다면 이제 인덱스 1인 3을 이용하여 나올 수 있는 경우의 수는 5 (8-3), 11(8+3) 이렇게 두개이다.

이후 인덱스 2인 15 라면 만들 수 있는 것은 이전까지 만들 수 있던 5와 11을 사용하여

20( 5+15), -10(5-15), 26(11+15), -4(11-15) 이다.

여기에서 0이상 20이하인 수는 20이다.

즉. 각 인덱스까지 사용할 수 있는 경우의 수로 그 다음 인덱스에서 현재 arr의 값을 덧셈 또는 뺄셈을 하여 나온 결과를 dp에 계속 기록해야나가는 것이다.

for (let i = 1; i < n - 1; i++) {
        const currentValue = arr[i];
        for (let j = 0; j <= 20; j++) {
            if (dp[i - 1][j] !== 0) {
                const plus = j + currentValue;
                const minus = j - currentValue;
                if (plus <= 20) {
                    dp[i][plus] += BigInt(dp[i - 1][j]);
                }
                if (minus >= 0) {
                    dp[i][minus] += BigInt(dp[i - 1][j]);
                }
            }
        }
    }

주의할 점은, 출력에 나온 조건인 '만들 수 있는 올바른 등식의 개수를 출력한다. 이 값은 263-1 이하이다.' 을 활용하여 각 인덱스를 BigInt로 기록해야한다는 것이다.

정답 코드

const main = (n, arr) => {
    const dp = Array.from({ length: n - 1 }, () =>
        Array.from({ length: 21 }, () => BigInt(0))
    );
    const answer = arr[arr.length - 1];
    dp[0][arr[0]] = BigInt(1);

    for (let i = 1; i < n - 1; i++) {
        const currentValue = arr[i];
        for (let j = 0; j <= 20; j++) {
            if (dp[i - 1][j] !== 0) {
                const plus = j + currentValue;
                const minus = j - currentValue;
                if (plus <= 20) {
                    dp[i][plus] += BigInt(dp[i - 1][j]);
                }
                if (minus >= 0) {
                    dp[i][minus] += BigInt(dp[i - 1][j]);
                }
            }
        }
    }
    console.log(dp[n - 2][answer].toString());
};

const input = require('fs')
    .readFileSync(process.platform === 'linux' ? '/dev/stdin' : './input.txt')
    .toString()
    .trim()
    .split('\n');

const n = +input[0];
const arr = input[1].split(' ').map((v) => +v);
main(n, arr);

 

'코딩 테스트 > 백준' 카테고리의 다른 글

16932 모양 만들기  (0) 2025.01.04
13398 연속합2  (0) 2025.01.04
12869 뮤탈리스크  (0) 2025.01.03
2133 타일 채우기  (0) 2025.01.03
2225 합분해 (자바스크립트)  (0) 2025.01.03