2 분 소요

2차원동전뒤집기 (프로그래머스 Level 3)

https://school.programmers.co.kr/learn/courses/30/lessons/131703

문제를 보고 곰곰히 생각해본 결과, 브루트 포스로 풀 수 있는 문제라 생각하였으나
(조건 : 길이 <= 10)
막상 구현에서 답이 막혀버렸다
‘가능한 모든 경우의 수를 탐색해야 하며’, ‘그것이 가능한지 여부를 체크’ 한다는 부분에
백기를 들었던 것 같다

검색을 해보니 비트마스킹과 간단한 수학적 지식을 통해 답을 이끌어내는 방식을 취할 수 있었는데

  1. ‘모든 행 n개를 뒤집는 경우의 수’는 1 « n 이다 (2^n)
  2. 각 경우의 수에 해당하는 mask 수를 ‘행’에 대하여 ‘비트마스킹’ 체크를 함으로서
    모든 행이 뒤집히는 각 경우의 수를 구할 수 있다
    => rowMask를 예로 들자면,
    rowMask : 1 ~ 1 « n 까지 반복
    반복문 i : 1 ~ n 까지 반복하며
    각 행이 뒤집히는 경우의 수를 체크(rowMask % (1 « i))
    rowMask가 0이면, 모든 행은 뒤집히지 않음(000)
    1이면, ‘첫’ 행만 뒤집힘 (001)
    2이면, ‘두번째 행만 뒤집힘 (010)

    7이면 ‘1,2,3’ 행이 뒤집힘(111)

이런식으로 가능한 모든 행과 모든 열에 대하여
경우의 수를 구하는 문제이다

문제가 막막하더라도 좀 더 다양한 방법으로 생각을 해봐야겠다고 다시금 느끼게 되었다

Code

#include <vector>
#include <algorithm>
#include <climits>

using namespace std;

// 행을 뒤집는 도우미 함수
void flipRow(vector<vector<int>>& matrix, int row)
{
	for (int j = 0; j < matrix[0].size(); j++)
	{
		matrix[row][j] = 1 - matrix[row][j];
	}
}

// 열을 뒤집는 도우미 함수
void flipColumn(vector<vector<int>>& matrix, int col)
{
	for (int i = 0; i < matrix.size(); i++)
	{
		matrix[i][col] = 1 - matrix[i][col];
	}
}

// 두 행렬이 동일한지 확인하는 함수
bool areEqual(const vector<vector<int>>& mat1, const vector<vector<int>>& mat2)
{
	for (int i = 0; i < mat1.size(); i++)
	{
		for (int j = 0; j < mat1[0].size(); j++)
		{
			if (mat1[i][j] != mat2[i][j])
			{
				return false;
			}
		}
	}
	return true;
}

int solution(vector<vector<int>> beginning, vector<vector<int>> target) {
	int n = beginning.size();
	int m = beginning[0].size();
	int answer = INT_MAX;

	// 모든 행 뒤집기 조합을 시도
	// 각 line의 모든 경우의 수가 1 << n이기에 이 이상 시도하였는데 발견하지 못하는 경우
	// 맞추는 것이 불가능하다 판단
	for (int rowMask = 0; rowMask < (1 << n); rowMask++)
	{
		vector<vector<int>> temp = beginning;
		int flipCount = 0;

		// rowMask를 기반으로 행을 뒤집기
		for (int i = 0; i < n; i++)
		{
			// rowMask가 1 ~ 1 << n 까지의 수를 '1'부터 증가하며 모든 경우의 수를 포함
			// 그걸 비트 마스킹을 통하여 '해당 번째 수'에서 '뒤집을 행'을 확인
			// -> 모든 '행'들이 각각 뒤집어 지는 경우의 수를 확인이 가능
			// 
			// 비트 마스킹 확인하기
			if (rowMask & (1 << i))
			{
				flipRow(temp, i);
				flipCount++;
			}
		}

		// 모든 열 뒤집기 조합을 시도
		for (int colMask = 0; colMask < (1 << m); colMask++)
		{
			vector<vector<int>> tempColFlip = temp;
			int currentFlipCount = flipCount;

			// colMask를 기반으로 열을 뒤집기
			for (int j = 0; j < m; j++)
			{
				if (colMask & (1 << j))
				{
					flipColumn(tempColFlip, j);
					currentFlipCount++;
				}
			}

			// 현재 구성과 target이 일치하는지 확인
			if (areEqual(tempColFlip, target))
			{
				answer = min(answer, currentFlipCount);
			}
		}
	}

	// 해결책을 찾지 못한 경우 -1 반환
	if (answer == INT_MAX)
	{
		return -1;
	}

	return answer;
}

댓글남기기