[C++]백준1938번 통나무 옮기기

3 minute read

문제는 다음과 같다.

오늘은 백준1938번 통나무 옮기기 문제를 풀어보도록 하자.

풀다가 통나무에 깔려 죽을뻔했다. 큐 관리는 간단했으나 구현부분이 너무 까다로웠기 때문이다.

우선 처음 통나무,목적지의 좌표와 모양을 체크했다. 통나무 중심점의 좌표와 모양 (가로:0, 세로:1)을 큐에 넣어주고 목적지의 좌표와 모양을 변수에 저장해주었다.

그리고 visit배열을 3차원으로 해주었는데 그 이유는 좌표값과 모양을 체크해줘야 하기 때문이다. 만일 visit[0][2][1]이면 y=2, x=1 , 가로모양이라는 뜻이고

visit[1][2][1]이면 y=2, x=1, 세로모양이라는 뜻이 된다. 즉, 좌표 중복을 체크하되 모양까지 체크해줘야 하는 것이다.

그 후 BFS를 큐 사이즈마다 돌려주었다. 왜냐하면 최솟값을 찾는 것이기 때문에 큐의 턴 관리를 해주어야 한다. 즉, 상하좌우턴 5번을 하고 answer++;를 하며

한 번 움직였다고 체크를 해주는게 아니라 들어있는 모든 큐를 각각 상하좌우턴 5번을 하고 answer++;를 해주어야 한다.

그리고 move함수를 통하여 상하좌우를 구현하였고 턴은 중심점이 바뀌지 않고 모양만 바뀌므로 따로 구현해주었다.

                                     [코드]
#include <iostream>
#include <queue>
using namespace std;

char map[50][50];
bool visit[2][50][50];//up,down,left,right,turn
int dir[8][2] = { {-1,0},{0,1},{1,0},{0,-1},{-1,-1},{-1,1},{1,1},{1,-1} };
//북,동,남,서,북서,북동,남동,남서
int N, answer = 0, answer_y, answer_x, answer_shape;
struct pos {
	int y;
	int x;
	int shape;//0 : 가로, 1 : 세로
};
queue<pos>Q, answer_Q;

bool Inbound(int y, int x) {
	return y >= 0 && x >= 0 && y < N && x < N;
}

void check_shape() {
	int y = Q.front().y;
	int x = Q.front().x;
	int shape = Q.front().shape;

	Q.pop();

	if (y + 1 == Q.front().y) {//세로
		y = Q.front().y;
		x = Q.front().x;
		shape = 1;
		Q.push({ y,x,shape });
		visit[1][y][x] = true;
	}
	else {//가로
		y = Q.front().y;
		x = Q.front().x;
		shape = 0;
		Q.push({ y,x,shape });
		visit[0][y][x] = true;
	}
	Q.pop(); Q.pop();

	y = answer_Q.front().y;
	x = answer_Q.front().x;
	shape = answer_Q.front().shape;

	answer_Q.pop();

	if (y + 1 == answer_Q.front().y) {//세로
		answer_y = answer_Q.front().y;
		answer_x = answer_Q.front().x;
		answer_shape = 1;
	}
	else {//가로
		answer_y = answer_Q.front().y;
		answer_x = answer_Q.front().x;
		answer_shape = 0;
	}
}

bool move(int y, int x, int shape, int i) {
	if (shape == 1) {//세로
		if (!visit[shape][y][x]) {
			if (i == 0) {//상
				y += dir[i][0];

				if (Inbound(y, x)) {
					if (map[y][x] != '1') {
						return true;
					}
				}
			}
			else if (i == 1 || i == 3) {//우, 좌
				int y_1 = y + dir[0][0];
				int y_2 = y + dir[2][0];

				if (map[y_1][x] != '1' && map[y][x] != '1' && map[y_2][x] != '1') {
					return true;
				}
			}
			else {//하
				y += dir[i][0];

				if (Inbound(y, x) && map[y][x] != '1') {
					return true;
				}
			}
		}
	}
	else {//가로
		if (!visit[shape][y][x]) {
			if (i == 0 || i == 2) {//상,하
				int x_1 = x + dir[1][1];
				int x_2 = x + dir[3][1];

				if (map[y][x_1] != '1' && map[y][x] != '1' && map[y][x_2] != '1') {
					return true;
				}
			}
			else if (i == 1) {//우
				x += dir[i][1];

				if (Inbound(y, x)) {
					if (map[y][x] != '1') {
						return true;
					}
				}
			}
			else {//좌
				x += dir[i][1];

				if (Inbound(y, x)) {
					if (map[y][x] != '1') {
						return true;
					}
				}
			}
		}
	}
	return false;
}

bool bfs() {
	while (!Q.empty()) {
		answer++;
		int size_of_Q = Q.size();

		for (int m = 0; m < size_of_Q; m++) {
			int y = Q.front().y;
			int x = Q.front().x;
			int shape = Q.front().shape;

			Q.pop();

			for (int i = 0; i < 4; i++) { //상,우,하,좌
				int my = y + dir[i][0];
				int mx = x + dir[i][1];

				if (!Inbound(my, mx) || map[my][mx] == '1') continue;

				if (move(my, mx, shape, i)) {
					if (my == answer_y && mx == answer_x && shape == answer_shape) {
						return true;
					}
					Q.push({ my,mx,shape });
					visit[shape][my][mx] = true;
				}
			}
			int cnt = 0;
			for (int i = 0; i < 8; i++) {//턴
				int t_y = y + dir[i][0];
				int t_x = x + dir[i][1];

				if (Inbound(t_y, t_x)) {
					if (map[t_y][t_x] != '1') {
						cnt++;
					}
				}
			}
			if (cnt == 8) {
				if (shape == 1) {
					if (!visit[0][y][x]) {
						Q.push({ y,x,0 });
						visit[0][y][x] = true;
					}
				}
				else {
					if (!visit[1][y][x]) {
						Q.push({ y,x,1 });
						visit[1][y][x] = true;
					}
				}
			}
		}
	}
	return false;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> N;

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> map[i][j];
			if (map[i][j] == 'B') {
				Q.push({ i,j,-1 });
			}
			if (map[i][j] == 'E') {
				answer_Q.push({ i,j,-1 });
			}
		}
	}
	check_shape();//처음 위치 파악
	if (bfs()) {
		cout << answer;
	}
	else {
		cout << 0;
	}
}

Tags:

Categories:

Updated: