비트마스킹 비밀 지도-프로그래머스-레벨1

비트마스킹의 기초를 연습해 보자

Category: 알고리즘 문제풀이 → 비트마스크
Difficulty: 초급
Date: 2025-01-20
Read Time: 6 mins read
Views: 조회

[1차] 비밀지도

문제 설명

네오는 평소 프로도가 비상금을 숨겨놓는 장소를 알려줄 비밀지도를 손에 넣었다. 그런데 이 비밀지도는 숫자로 암호화되어 있어 위치를 확인하기 위해서는 암호를 해독해야 한다. 다행히 지도 암호를 해독할 방법을 적어놓은 메모도 함께 발견했다.

  1. 지도는 한 변의 길이가 n인 정사각형 배열 형태로, 각 칸은 “공백”(“ “) 또는 “벽”(“#”) 두 종류로 이루어져 있다.
  2. 전체 지도는 두 장의 지도를 겹쳐서 얻을 수 있다. 각각 “지도 1”과 “지도 2”라고 하자. 지도 1 또는 지도 2 중 어느 하나라도 벽인 부분은 전체 지도에서도 벽이다. 지도 1과 지도 2에서 모두 공백인 부분은 전체 지도에서도 공백이다.
  3. “지도 1”과 “지도 2”는 각각 정수 배열로 암호화되어 있다.
  4. 암호화된 배열은 지도의 각 가로줄에서 벽 부분을 1, 공백 부분을 0으로 부호화했을 때 얻어지는 이진수에 해당하는 값의 배열이다.

네오가 프로도의 비상금을 손에 넣을 수 있도록, 비밀지도의 암호를 해독하는 작업을 도와줄 프로그램을 작성하라.

입출력 예제 시각화

지도 1 지도 2 비밀지도
01001(2) 9 OR ( | ) 11110(2) 30 = #####
10100(2) 20 00001(2) 1 # # #
11100(2) 28 10101(2) 21 ### #
10010(2) 18 10001(2) 17 # ##
01011(2) 11 11100(2) 28 #####

입력 형식

입력으로 지도의 한 변 크기 n 과 2개의 정수 배열 arr1, arr2가 들어온다.

  • 1 ≦ n ≦ 16
  • arr1, arr2는 길이 n인 정수 배열로 주어진다.
  • 정수 배열의 각 원소 x를 이진수로 변환했을 때의 길이는 n 이하이다. 즉, 0 ≦ x ≦ 2n - 1을 만족한다.

출력 형식

원래의 비밀지도를 해독하여 ‘#’, 공백으로 구성된 문자열 배열로 출력하라.

입출력 예제

n arr1 arr2 출력
5 [9, 20, 28, 18, 11] [30, 1, 21, 17, 28] ["#####","# # #", "### #", "# ##", "#####"]
6 [46, 33, 33, 22, 31, 50] [27, 56, 19, 14, 14, 10] ["######", "### #", "## ##", " #### ", " #####", "### # "]

해설

전형적인 비트마스킹 문제이다. 많은 경우 서버의 채점 환경은 ‘Little Endian’이기 때문에 n - 1번째 비트부터 체크하면서 내려와야 한다. 만약 그렇게 냈는데 안 됐다면 서버가 ‘Big Endian’인 특이 케이스일 수 있으니 0번째 비트부터 체크하면 된다.

격자가 있든 말든 본질은 탐색도 그래프도 아닌 비트마스킹 문제이다. 그냥 냅다 두 벡터를 OR한 새로운 벡터를 만들고, 그냥 for문 돌려서 비트마스킹으로 추출한다.

비트 추출 원리

(bool)((x >> i) & 1)

이것의 뜻은 x를 i만큼 오른쪽으로 밀고, 그것과 1을 AND연산한 후 1비트만큼 잘라내어 불리언으로 쓰겠다는 뜻이다. 반드시 AND 연산하는 둘의 타입이 같아야 일어날지도 모르는 사고를 막을 수 있다.

  1. 원하는 비트가 x의 첫 1비트에 올 만큼 밀어준다.
  2. 1과 AND 연산을 한다.
  3. (bool)을 씌워 1비트만 잘라낸다.

그렇게 했을 때를 uint8_t x = 128일 때 x의 오른쪽에서 8번째 비트를 가져오는 경우로 한번 생각해 보자. 8비트 부호 없는 정수 128은 이렇게 표현 가능하다.

10000000
       ^
       여기가 x의 첫 비트

이 상황에서 비트를 밀어보자.

10000000
       ^ x >> 0, (bool)((x >> 0) & 1) == false 
10000000
      ^  x >> 1, (bool)((x >> 1) & 1) == false  
10000000
     ^   x >> 2, (bool)((x >> 2) & 1) == false 
10000000
    ^    x >> 3, (bool)((x >> 3) & 1) == false 
10000000
   ^     x >> 4, (bool)((x >> 4) & 1) == false 
10000000
  ^      x >> 5, (bool)((x >> 5) & 1) == false 
10000000
 ^       x >> 6, (bool)((x >> 6) & 1) == false 
10000000
^        x >> 7, (bool)((x >> 7) & 1) == true

와 같이 비트가 잘 추출된다. 이 문제는 주어진 N비트만큼 추출하되 오른쪽부터 왼쪽으로 기계어 어순으로 읽은 후 왼쪽부터 오른쪽으로 사람 어순으로 '#'=1, ' '=0으로 가공해서 던져주는 것이다.

풀이

#include <string>
#include <vector>
#include <algorithm>

using namespace std;

string parse_n_bits(int x, int n) {
    string s;
    for(int i = n - 1; i >= 0; i--) {
        if((bool)((x >> i) & 1)) {
            s += "#";
        } else {
            s += " ";
        }
    }
    return s;
}


vector<string> solution(int n, vector<int> arr1, vector<int> arr2) {
    vector<string> answer;
    vector<int>    with_or_gate(arr1);
    for(int i = 0; i < with_or_gate.size(); i++) with_or_gate[i] |= arr2[i];

    for(int i = 0; i < with_or_gate.size(); i++) {
        answer.push_back(parse_n_bits(with_or_gate[i], n));
    }
    return answer;
}

참고 사항

매우 난이도가 낮기 때문에 방심할 수 있으나, 언제 비트를 잘라내고 언제 OR 연산하는지 유심히 볼 필요가 있다. 당당하게 날림으로 풀었다가 큰일이 날 수도 있으니 주의하고 또 주의하자.

Document Classification

Subcategory
비트마스크
Keywords
프로그래머스 알고리즘 비트마스크
Difficulty
초급
Permalink
https://gg582.github.io/codingtest/2026-01-20-%5B%EB%B9%84%ED%8A%B8%EB%A7%88%EC%8A%A4%ED%82%B9%5D-%EB%B9%84%EB%B0%80-%EC%A7%80%EB%8F%84-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%A0%88%EB%B2%A81/

Citation

이윤진(Lee Yunjin) (2025). [비트마스킹] 비밀 지도-프로그래머스-레벨1. 윤진의 IT 블로그. Retrieved from https://gg582.github.io/codingtest/2026-01-20-%5B%EB%B9%84%ED%8A%B8%EB%A7%88%EC%8A%A4%ED%82%B9%5D-%EB%B9%84%EB%B0%80-%EC%A7%80%EB%8F%84-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%A0%88%EB%B2%A81/
── 하략 ──