[BOJ] 18808 스티커 붙이기 (node.js)

2025. 1. 23. 13:41·👩‍💻 Algorithm
BOJ 문제 18808번의 풀이 과정을 작성한 게시글입니다.

 

링크

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

 

문제

혜윤이는 최근에 다양한 대회를 참여하면서 노트북에 붙일 수 있는 스티커들을 많이 받았다. 스티커는 아래와 같이 사각 모눈종이 위에 인쇄되어 있으며, 스티커의 각 칸은 상하좌우로 모두 연결되어 있다. 또한 모눈종이의 크기는 스티커의 크기에 꼭 맞아서, 상하좌우에 스티커가 포함되지 않는 불필요한 행이나 열이 존재하지 않는다.

아래는 올바른 모눈종이의 예시이다. 주황색 칸은 스티커가 붙은 칸을, 하얀색 칸은 스티커가 붙지 않은 칸을 나타낸다.

 

 

혜윤이는 자신의 노트북에 이 스티커들을 붙이기로 했다. 혜윤이의 노트북은 마침 직사각형 모양이고, 스티커가 인쇄된 모눈종이와 같은 간격으로 격자가 그려져 있다. 혜윤이는 스티커들을 먼저 받았던 것부터 차례대로 격자에 맞춰서 붙이려고 한다.

혜윤이가 스티커를 붙이는 방법은 다음과 같다.

 

1. 스티커를 회전시키지 않고 모눈종이에서 떼어낸다.

2. 다른 스티커와 겹치거나 노트북을 벗어나지 않으면서 스티커를 붙일 수 있는 위치를 찾는다. 혜윤이는 노트북의 위쪽부터 스티커를 채워 나가려고 해서, 스티커를 붙일 수 있는 위치가 여러 곳 있다면 가장 위쪽의 위치를 선택한다. 가장 위쪽에 해당하는 위치도 여러 곳이 있다면 그중에서 가장 왼쪽의 위치를 선택한다.

3. 선택한 위치에 스티커를 붙인다. 만약 스티커를 붙일 수 있는 위치가 전혀 없어서 스티커를 붙이지 못했다면, 스티커를 시계 방향으로 90도 회전한 뒤 2번 과정을 반복한다.

4. 위의 과정을 네 번 반복해서 스티커를 0도, 90도, 180도, 270도 회전시켜 봤음에도 스티커를 붙이지 못했다면 해당 스티커를 붙이지 않고 버린다.

 

아래의 예시를 통해 스티커를 붙이는 과정을 이해해보자. 노트북은 세로 5칸, 가로 4칸 크기이고, 혜윤이가 가지고 있는 스티커들은 아래와 같다. 왼쪽에서 오른쪽 순으로 스티커를 붙일 것이다.

 

 

1. 첫 번째 스티커는 회전 없이 온전히 붙일 수 있는 공간이 아래와 같이 6곳이 있다.

 

이 중에서 가장 위쪽의 위치, 가능한 가장 위쪽의 위치가 여러 개이면 그 중에서 가장 왼쪽의 위치는 첫 번째이다. 스티커를 붙인 후 노트북의 모양은 아래와 같다.

 

 

2. 두 번째 스티커는 회전 없이 온전히 붙일 수 있는 공간이 없다. 그러나 시계 방향으로 90도 회전한 후에는 붙일 수 있는 공간이 1개 생긴다. 해당 공간에 스티커를 붙인 후 노트북의 모양은 아래와 같다.

 

3. 세 번째 스티커는 스티커를 시계방향으로 0, 90, 180, 270도 회전시킨 모양에 대해 전부 확인을 해도 스티커를 붙일 수 있는 공간이 없다. 그러므로 해당 스티커를 붙이지 않고 버린다.

4. 네 번째 스티커는 스티커를 시계방향으로 0, 90, 180도 회전 시킨 모양에 대해 온전히 붙일 수 있는 공간이 없다. 그러나 시계 방향으로 270도 회전한 후에는 공간이 1개 생긴다. 스티커를 붙인 후 노트북의 모양은 아래와 같다. 최종적으로 노트북의 18칸이 스티커로 채워졌다.

 

 

 

혜윤이는 스티커를 다 붙인 후의 노트북의 모습이 궁금해졌다. 노트북의 크기와 스티커들이 주어졌을 때 스티커들을 차례대로 붙이고 난 후 노트북에서 몇 개의 칸이 채워졌는지 구해보자.

 

풀이 과정

접근법 : 브루트 포스

구해야 하는 것은 모든 스티커를 다 붙였을 때의 노트북에 붙은 칸의 갯수이다.

 

노트북의 크기와 스티커의 크기를 고려했을 때, 최대 크기로 완전 탐색을 해도 40x40x10x10x100 = O(16x10^6) 이므로 시간 초과가 발생하지 않는다.

 

따라서 브루트 포스로 왼쪽과 위를 우선적으로 스티커를 붙일 위치를 지정하고, 현재 위치에서 스티커 크기만큼 순회하여 스티커를 붙일 수 있는지 flag를 통해 판단해 주었다.

 

또, 현재 위치에서 스티커를 못 붙이면 배열을 회전하는 함수를 통해 회전시켜 주었다.

 

 

코드

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

const [N, M, K] = input.shift().split(" ").map(Number);
const notebook = Array.from({ length: N }, () => Array(M).fill(0));

const rotate = (arr) => {
  const copy = Array.from({ length: arr[0].length }, () => Array(arr.length).fill(0));

  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr[0].length; j++) {
      copy[j][arr.length - i - 1] = arr[i][j];
    }
  }

  return copy;
};

for (let k = 0; k < K; k++) {
  const [a, b] = input.shift().split(" ").map(Number);
  let sticker = input.splice(0, a).map((x) => x.split(" ").map(Number));

  let isAttached = false;

  for (let d = 0; d < 4; d++) {
    let sr = sticker.length;
    let sc = sticker[0].length;

    for (let i = 0; i <= N - sr; i++) {
      for (let j = 0; j <= M - sc; j++) {
        let isPossible = true;

        for (let k = 0; k < sr; k++) {
          for (let l = 0; l < sc; l++) {
            if (sticker[k][l] === 1) {
              if (i + k < 0 || i + k >= N || j + l < 0 || j + l >= M) continue;
              if (notebook[i + k][j + l] !== 0) {
                isPossible = false;
                break;
              }
            }
          }

          if (!isPossible) break;
        }

        if (isPossible) {
          isAttached = true;

          for (let r = 0; r < sr; r++) {
            for (let c = 0; c < sc; c++) {
              if (sticker[r][c]) {
                notebook[i + r][j + c] = 1;
              }
            }
          }

          break;
        }
      }

      if (isAttached) break;
    }

    if (isAttached) break;

    sticker = rotate(sticker);
  }
}

let answer = 0;

for (let i = 0; i < N; i++) {
  for (let j = 0; j < M; j++) {
    if (notebook[i][j]) answer++;
  }
}

console.log(answer);

 

후기

로직은 쉬우나 이런 문제는 좌표 값의 범위를 설정하는게 헷갈린다.

또 좌표의 변수가 너무 많아서 헷갈리기 쉽기 때문에 집중하고 코딩해야 할 것 같다.

'👩‍💻 Algorithm' 카테고리의 다른 글

[BOJ] 1584 게임 (node.js)  (2) 2025.01.27
[BOJ] 16928 뱀과 사다리 게임 (node.js)  (2) 2025.01.24
[BOJ] 27172 수 나누기 게임 (node.js)  (0) 2025.01.22
[BOJ] 1520 내리막 길 (node.js)  (0) 2025.01.21
[BOJ] 2056 작업 (node.js)  (2) 2025.01.20
'👩‍💻 Algorithm' 카테고리의 다른 글
  • [BOJ] 1584 게임 (node.js)
  • [BOJ] 16928 뱀과 사다리 게임 (node.js)
  • [BOJ] 27172 수 나누기 게임 (node.js)
  • [BOJ] 1520 내리막 길 (node.js)
fe developer
fe developer
Every second counts 🫧
  • fe developer
    메리의 코딩일기장
    fe developer
  • 전체
    오늘
    어제
    • 분류 전체보기 (27)
      • ☘️ Front end (4)
        • 🌱 React (0)
        • 🌱 Javascript (4)
        • ✨ Deep dive (0)
      • 🪐 우아한테크코스 (0)
      • 👩‍💻 Algorithm (14)
      • 💻 CS (9)
        • 🫧 네트워크 (6)
        • 🫧 운영체제 (0)
        • 🫧 컴퓨터구조 (3)
      • 💭 회고록 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Algorithm
    dfs
    네트워크
    실행 컨텍스트
    JavaScript
    2024
    network
    CS
    DP
    computer structure
    BFS
    BOJ
    연간회고록
    this
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
fe developer
[BOJ] 18808 스티커 붙이기 (node.js)
상단으로

티스토리툴바