GitHub ID : soohyun-dev
윤수현의 개발 공간
GitHub ID : soohyun-dev
전체 방문자
오늘
어제
  • 분류 전체보기 (918)
    • 성장기록 (49)
      • 성장기록 (3)
      • 우아한테크코스 (16)
      • 프로젝트 (15)
      • TIL (14)
      • 테오의 스프린트 (1)
    • 프로그래밍언어 (88)
      • C언어 (14)
      • HTML\CSS (12)
      • JavaScript (7)
      • React (23)
      • Python (11)
      • JAVA (14)
      • TypeScript (6)
    • 알고리즘 공부 (736)
      • 코드업 - 파이썬 (108)
      • 백준 - 파이썬 (468)
      • 백준 - 자바스크립트 (125)
      • 프로그래머스 - 파이썬 (1)
      • 프로그래머스 - 자바스크립트 (34)
    • 책 리뷰 (9)
      • 프로그래밍 (3)
      • 독서 (6)
    • 전자기기 (1)
    • 일상, 일기 (18)
    • 기술 세미나 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • javascript
  • 코딩테스트
  • 파이썬
  • 독해
  • PYTHON
  • 프로그래밍언어
  • 프로그래머스풀이
  • 코딩
  • 백준
  • 프로그래머스자바스크립트
  • 코드업파이썬
  • 프로그래머스
  • 프론트엔드
  • 자바스크립트
  • 백준풀이
  • 코드업
  • 영어독해
  • 백준파이썬
  • 코테
  • 영어

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
GitHub ID : soohyun-dev

윤수현의 개발 공간

백준/ Gold 2 문제 , 백준 Node.js 자바스크립트 12100 2048 (Easy) [ 백트래킹, DFS, 구현 ] 삼성 SW 역량 테스트 기출 문제
알고리즘 공부/백준 - 자바스크립트

백준/ Gold 2 문제 , 백준 Node.js 자바스크립트 12100 2048 (Easy) [ 백트래킹, DFS, 구현 ] 삼성 SW 역량 테스트 기출 문제

2022. 12. 14. 10:02

백준/ Gold 2 문제 , 백준 Node.js 자바스크립트 11568 민균이의 계략 [ 백트래킹, DFS, 구현 ] 삼성 SW 역량 테스트 기출 문제 

 

 

 

✔️Check Point !   ( 해당사항 ✓체크 )

1. 막힘 없이 수월하게 풀린 문제인가?

2. 1시간이내로 풀렸던 문제인가?

3. 1시간 이상 or 며칠을 두고 풀어봤더니 풀린 문제인가?

4. 시간을 써도 도무지 풀 수 없는 문제인가?

5. 솔루션을 찾아봤는가?

-------------------------------------------------------------------------------------------

난이도 체감 🧑‍💻
1. 최상
2. 상
3. 중
4. 하


이해도 🙆‍♂️
1. 완벽히 이해
2. 다소 헷갈리는 부분들이 있음
3. 이해 못함

 

 

문제 출처 🏠

https://www.acmicpc.net/problem/12100

 

12100번: 2048 (Easy)

첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2

www.acmicpc.net

 

 

문제풀이 소감 🧑‍💻

 

정말 고려해야할 것들이 너무 많아서 어렵게 느껴졌다.

 

시간을 쏟을수록 쓴 시간이 아까워서 더 달려들게 되었던 문제다 ㅋㅋㅋ

 

그래도 결국 힌트없이 제 힘으로 푸는데 성공!!!! 

 

진짜 '맞았습니다!!' 떴을때 너무 기뻤다 😚😚

 

 

알고보니 삼성 SW 역량 기출문제였음..... 어쩐지 빡세더라.

 

 

 

 

 

 

 

요구사항 📋

 

* 게임 방법을 알아야하므로 문제 설명 필수 참고

 

  • 첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다.
  • 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다.
  • 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다.
  • 블록에 쓰여 있는 수는 2보다 크거나 같고, 1024보다 작거나 같은 2의 제곱꼴이다.
  • 블록은 적어도 하나 주어진다.
  • 최대 5번 이동시켜서 얻을 수 있는 가장 큰 블록을 출력한다.

 

 

 

주의 ❗

 

4
0 2 0 2
2 0 0 0
0 2 2 0
2 0 2 2

 

문제 해결의 반례를 찾기 위해 만들어본 예시인데, 이 반례를 위,오른쪽,아래,왼쪽으로 각각 이동시켰을때

 

한줄이 다 4로 되어있는지를 확인하자.

 

 

위로 밀 경우

4
4 4 4 4
0 0 0 0 
0 0 0 0
0 0 0 0

 

오른쪽으로 밀 경우

4
0 0 0 4
0 0 0 4 
0 0 0 4
0 0 0 4

 

아래로 밀 경우

4
0 0 0 0
0 0 0 0 
0 0 0 0
4 4 4 4

 

왼쪽으로 밀 경우

4
4 0 0 0
4 0 0 0 
4 0 0 0
4 0 0 0

 

각각 위 경우들이 나와야한다.

 


 

또한,

 

4
4 2 2 4
0 0 0 0
0 0 0 0
0 0 0 0

이걸 왼쪽으로 밀었을때

 

 

4
8 4 0 0
0 0 0 0
0 0 0 0
0 0 0 0

 

이게 나오면 안된다.

 

 

4
4 4 4 0
0 0 0 0
0 0 0 0
0 0 0 0

 

이게 올바른 정답.

 

이유는 한 턴에 합쳐졌던 숫자는 다시 합치는데 쓰일 수 없다.

 

 

내가 틀렸던 부분들 정리

 

  • 한 턴에 합쳐졌던 숫자는 그 턴 내에서 다시 합쳐지지 못한다.
  • 합치는 것이 아닌 그냥 이동 시켜주는 경우  조건문 잘 생각 (해결 전략에서 자세히 설명)
  • 숫자들 끝까지 잘 밀어주기

 

 

해결 전략 📝

 

 

1) deep copy

 

 이 문제에서 진짜 중요한 부분 중 하나가 deep copy 부분이다.

 

 

dfs 로 여러 경우를 확인해보기 때문에 원본 배열의 손상을 필수적으로 막아줘야한다. 

 

이 방법에는 deep copy가 사용된다. 얕은 복사를 해버려면 원본 배열에 손상이 생긴다.

 

 

 

자바스크립트에서 deep copy 하는 방법은 여럿 있지만, 이 방법이 가장 간편하다고 생각한다.

 

바로 copy 할 배열을 stringfy 해준다음에 parse 해주는 것이다.

 

배열이라 깊은 복사가 가능하며, 이 과정에서 객체에 대한 참조가 끊기기 때문에 이 점을 deep copy로 이용한 것이다.

 

속도가 느릴 수도 있으나 문제 풀이에 영향이 가는정도도 아니다.

 

이 과정을 거쳐줘야지 원본 값에 대한 손실이 발생하지 않으므로 특히 신경써서 구현해야하는 부분이다.

 

초기 dfs를 호출하는 부분에서만 사용하는 것이 아닌, dfs 를 재귀 호출 할때도 반드시 deep copy 해준 배열을 넣어주자.

 

 

2) 미는 방향 확인

 

 

우선 미는 방향에 따라 확인해야할 시작 인덱스들이 다르다.

 

 

0 번부터 3번까지 [ 위쪽, 오른쪽, 아래쪽, 왼쪽 ] 시계방향 순이다.

 

 

각 방향에 따른 확인해야할 인덱스는 다음과 같다.

 


 

 

위쪽 ⬆️

 

 

 

오른쪽 ➡️

 

 

 

 

아래쪽 ⬇️

 

 

 

 

왼쪽 ⬅️

 

 

 

향하는 방향쪽부터 시작해서 반대방향으로 진행한다고 생각하면 쉽다.

 

향하는 방향의 끝부분이 바닥이라 생각하고 차례로 하나씩 넣어준다 생각.

 

 

3) 밀어서 합치기 || 이동

 

이 문제의 구현 부분중 가장 핵심인 부분이다.

 

아마 어렵다고 느껴지거나 반례가 통과하지 못한다면 거의 이 부분의 구현에서 문제가 있을 확률이 높다.

 

 

이동 시켜줄때의 경우는 두가지다.

 

1. 같은 숫자들끼리 만나 합쳐지기

2. 빈공간으로 이동하기

 

우선 이 두가지 경우를 while 문 조건문으로 두고 돌려준다.

 

 

 

1. 같은 숫자들끼리 만나 합쳐지기 부분에서 중요한 부분은

 

한 번 합쳐진 숫자들은 그 턴 내에서 다시 합쳐질 수 없다는 것이다. 

 

이 부분을 절대 놓치지 말자.

 

이 경우를 체크해주는 방법이 바로 visited 객체를 사용해서 방문 표시를 해주는 법이다.

 

합쳐지는 경우에 그 자리에 방문 표시를 해준다.

 

이후 그 자리로 다시 숫자가 합쳐지려고 해도 방문 표시가 되어있다면 합쳐지는 행위를 막아줄 수 있다.

 

또한, 이 문제의 결국 목적은 큰 숫자를 찾는 것이므로 합쳐진 뒤의 MAX값을 저장한다.

 

 

다음은 2. 빈공간으로 이동하기 이다.

 

이 부분은 간단하다.

 

말그대로 그냥 위치만 이동시켜주면 된다. 

 

놓치지 말아야할 점은 이동 후 이동전 자리를 0으로 만들어주는 것.

 

 

 

여기서 근데 중요한 점이 있다.

 

만약 2 0 0 2 를 왼쪽으로 밀 때 어떻게 되어야 하는가?

 

당연히 4 0 0 0 이 되어야한다.

 

하지만, 2. 빈공간으로 이동하기 에는 중간 2 0 0 2 이 0 0 부분을 그냥 이동시켜준다고 판단한다.

 

그리고 다시 while 문을 돌려버리면 뜬금없이 이 0이 1. 같은 숫자들끼리 만나 합쳐지기 조건문 내로 들어가서 0 부분에 방문표시를 해버리게 될 수도 있다. (내가한 실수...)

 

쉽게 말해 0 두개가 서로 합쳐져서 그 자리에 필요없는 방문표시를 해버려 다른 숫자가 진짜 합쳐져야 할 때 합쳐지지 못하는 상황이 생겨버린다.

 

 

그러므로 이러한 상황을 막기 위해 

 

 

while 문 내의 1. 같은 숫자들끼리 만나 합쳐지기 조건 문에 nowboard[mx][my] !== 0 을 필수적으로 넣어줘야한다.

 

0 0 두개가 만난 다면 그 부분은 합치지 않겠다라고 선언하는 것이다.

 

 

 

4) 재귀 호출

 

최대 5번까지의 이동만 허락하므로 재귀가 4번 까지 추가적으로 이뤄질때까지만 dfs를 호출한다.

 

cnt<4 를 넣어주게 되면 맨 초기 호출을 제외한 4번까지만 호출을 하고 더이상 호출을 하지않게 된다.

 

또한, 이 과정에서도 원본 배열의 손상을 막기 위해 deep copy를 사용해준다.

 

 

 

 

정답 💯

 

const input = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');

const [input_N, ...input_board] = input.map((v) => v.trim().split(' ').map(Number));

function solution(N, board) {
  const direction = [0, 1, 2, 3];
  const dr_x = [-1, 0, 1, 0];
  const dr_y = [0, 1, 0, -1];

  const dfs = (nowOrder, cnt, nowBoard) => {
    let visited = {};
    if (nowOrder === 0) {
      for (let j = 0; j < N; j++) {
        for (let i = 0; i < N; i++) {
          if (check(i, j, nowOrder)) continue;
          [nowBoard, visited] = move(i, j, dr_x[nowOrder], dr_y[nowOrder], nowBoard, visited);
        }
      }
    } else if (nowOrder === 1) {
      for (let i = 0; i < N; i++) {
        for (let j = N - 1; j >= 0; j--) {
          if (check(i, j, nowOrder)) continue;
          [nowBoard, visited] = move(i, j, dr_x[nowOrder], dr_y[nowOrder], nowBoard, visited);
        }
      }
    } else if (nowOrder === 2) {
      for (let j = 0; j < N; j++) {
        for (let i = N - 1; i >= 0; i--) {
          if (check(i, j, nowOrder)) continue;
          [nowBoard, visited] = move(i, j, dr_x[nowOrder], dr_y[nowOrder], nowBoard, visited);
        }
      }
    } else if (nowOrder === 3) {
      for (let i = 0; i < N; i++) {
        for (let j = 0; j < N; j++) {
          if (check(i, j, nowOrder)) continue;
          [nowBoard, visited] = move(i, j, dr_x[nowOrder], dr_y[nowOrder], nowBoard, visited);
        }
      }
    }
    direction.forEach((dr) => {
      if (cnt < 4) {
        const copy = JSON.parse(JSON.stringify(nowBoard));
        dfs(dr, cnt + 1, copy);
      }
    });
  };

  const check = (i, j, order) => {
    return i + dr_x[order] < 0 || i + dr_x[order] >= N || j + dr_y[order] < 0 || j + dr_y[order] >= N;
  };

  const move = (x, y, drX, drY, nowboard, visited) => {
    let [mx, my] = [x, y];
    while (nowboard[mx + drX][my + drY] === 0 || nowboard[mx + drX][my + drY] === nowboard[mx][my]) {
      if (nowboard[mx + drX][my + drY] === nowboard[mx][my] && nowboard[mx][my] !== 0) {
        if (visited[`${mx + drX}${my + drY}`] === undefined) {
          nowboard[mx + drX][my + drY] *= 2;
          nowboard[mx][my] = 0;
          visited[`${mx + drX}${my + drY}`] = true;
          MAX = Math.max(MAX, nowboard[mx + drX][my + drY]);
        }
        [mx, my] = [mx + drX, my + drY];
        if (mx + drX < 0 || mx + drX >= N || my + drY < 0 || my + drY >= N) break;
        if (nowboard[mx + drX][my + drY] !== 0) break;
      } else {
        nowboard[mx + drX][my + drY] = nowboard[mx][my];
        nowboard[mx][my] = 0;
        [mx, my] = [mx + drX, my + drY];
      }
      if (mx + drX < 0 || mx + drX >= N || my + drY < 0 || my + drY >= N) break;
    }

    return [nowboard, visited];
  };

  let MAX = 0;
  board.forEach((v) => {
    MAX = Math.max(MAX, ...v);
  });
  direction.forEach((dr) => {
    const copy = JSON.parse(JSON.stringify(board));
    dfs(dr, 0, copy);
  });
  if (N === 1) return board[0][0];

  return MAX;
}

console.log(solution(input_N[0], input_board));

 

반응형

'알고리즘 공부 > 백준 - 자바스크립트' 카테고리의 다른 글

백준/ Gold 5 문제 , 백준 Node.js 자바스크립트 9205 맥주 마시면서 걸어가기 [ BFS, 그래프 이론 ]  (1) 2023.04.11
백준/ Gold 2 문제 , 백준 Node.js 자바스크립트 17822 원판 돌리기 [ 구현, 시뮬레이션 ]  (0) 2023.02.14
백준/ Silver 2 문제 , 백준 Node.js 자바스크립트 11568 민균이의 계략 [ 이분탐색, LIS ]  (0) 2022.12.14
백준/ Gold 4 문제 , 백준 Node.js 자바스크립트 1806 부분합  (0) 2022.12.12
백준/ Gold 2 문제 , 백준 Node.js 자바스크립트 3066 브리징 시그널 [ 이분탐색, LIS ]  (0) 2022.12.12
    '알고리즘 공부/백준 - 자바스크립트' 카테고리의 다른 글
    • 백준/ Gold 5 문제 , 백준 Node.js 자바스크립트 9205 맥주 마시면서 걸어가기 [ BFS, 그래프 이론 ]
    • 백준/ Gold 2 문제 , 백준 Node.js 자바스크립트 17822 원판 돌리기 [ 구현, 시뮬레이션 ]
    • 백준/ Silver 2 문제 , 백준 Node.js 자바스크립트 11568 민균이의 계략 [ 이분탐색, LIS ]
    • 백준/ Gold 4 문제 , 백준 Node.js 자바스크립트 1806 부분합
    GitHub ID : soohyun-dev
    GitHub ID : soohyun-dev
    환영합니다!😊 이곳은 저의 개발에 관한 내용들을 정리하는 공간입니다. 알고리즘 풀이에도 관심이 많아요. 좋은 하루 되세요~! github : soohyun_dev

    티스토리툴바