알고리즘/백준

BOJ14391/ C++

내이름은 킹햄찌 2022. 1. 26. 18:21

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

 

14391번: 종이 조각

영선이는 숫자가 쓰여 있는 직사각형 종이를 가지고 있다. 종이는 1×1 크기의 정사각형 칸으로 나누어져 있고, 숫자는 각 칸에 하나씩 쓰여 있다. 행은 위에서부터 아래까지 번호가 매겨져 있고,

www.acmicpc.net

 

백준 온라인저지 14391번 문제입니다. 

비트마스킹을 이용해서 풀었습니다.

 

#include<iostream>
#include<string>
#define MAX 4

using namespace std;

int n, m;
int arr[MAX][MAX];

int max(int a, int b) {
	return a > b ? a : b;
}

void Input() {
	cin >> n >> m;
	string s;
	for (int i = 0; i < n; i++) {
		cin >> s;
		for (int j = 0; j < m; j++) {
			arr[i][j] = s[j] - '0';
		}
	}
}

void solution() {
	int ans = 0;
	for (int s = 0; s < (1 << (n*m)); s++) {
		int sum = 0;

		//가로
		for (int i = 0; i < n; i++) {

			int now = 0;
			for (int j = 0; j < m; j++) {

				int k = i * m + j;
				
				//가로인경우
				if ((s&(1 << k)) == 0) {
					now = now * 10 + arr[i][j];
				}
				else {
					sum += now;
					now = 0;
				}
			}
			sum += now;
		}

		//세로
		for (int j = 0; j < m; j++) {

			int now = 0;
			for (int i = 0; i < n; i++) {
				int k = i * m + j;

				//세로인경우
				if ((s&(1 << k))!=0) {
					now = now * 10 + arr[i][j];
				}

				else {
					sum += now;
					now = 0;
				}


			}
			sum += now;
		}
		ans = max(sum, ans);
	}
	cout << ans;
}

int main(void) {
	Input();
	solution();
}

아이디어

종이를 가로 세로로 자를 수 있는 모든 경우의 수를 다 확인을 해봐야하는데 그 잘려진 상태를 비트로 표현을 하여 계산을 해야함 n차 행렬을 모두 펴서 한줄의 비트로 표현을 해야함 예를들어

123                     0 0 0 0 0 0

456  같은 경우에는 1 2 3 4 5 6 과 같이 비트로 표현 할 수 있고 해당 영역이 가로로 잘렸는지 세로로 잘렸는지는 

0과 1으로 표현 할 수 있음 여기서는 0을 가로 1을 세로로 정하였음

가로 또는 세로 비트를 확인 할때 연속으로 표현된 비트가 있다면 앞의 숫자에 10을 곱하여 현재 수를 더함으로써

종이가 길게 잘렸을때의 숫자를 보장해줌 

 

브루트 포스로 풀 수 도 있으나 방법이 크게 다르지 않고 비트마스킹으로 푸는 방식이 깔끔해보여서 시도해보지 않았음