mojo's Blog

[백준 2151] 거울 설치 본문

백준/BFS, DFS

[백준 2151] 거울 설치

_mojo_ 2021. 6. 30. 19:12

문제 링크 => 2151번: 거울 설치 (acmicpc.net)

 

2151번: 거울 설치

첫째 줄에 집의 크기 N (2 ≤ N ≤ 50)이 주어진다. 다음 N개의 줄에는 N개의 문자로 집에 대한 정보가 주어진다. ‘#’는 문이 설치된 곳으로 항상 두 곳이며, ‘.’은 아무 것도 없는 것으로 빛은

www.acmicpc.net


BFS 문제이며 문제를 접근한 알고리즘은 다음과 같다.

 

1. 시작 지점의 방향은 -1로 설정해두고 그 이후로는 0~3(상하좌우) 가 되도록 구현하였다.

=> 이때, class Light 를 활용하여 위치(x, y), 방향(direction)을 설정하도록 하였고, 

queue<pair<Light,int>> q; 에서 int는 거울을 배치한 갯수를 담도록 설정하였다.

또한 시작지점의 방문처리도 해주었다. (1로 설정하였는데 배치한 갯수+1로 보면 된다.)

 

2. 시작 지점에서는 상하좌우로 이동하도록 하고 그 이후로는 direction 에 의존하여 이동하도록 하였다.

 

3. 시작 지점인 경우 )

(1) 다음 구역에서 '.' 을 발견한 경우 => Queue에 next 좌표와 방향, cnt 값을 그대로 push

(2) 다음 구역에서 '!'(거울) 을 발견한 경우 => 위아래 / 좌우 에 따라서 다음과 같이 Queue에 push한다.

예를들어서 위아래인 경우 거울은 좌우로 이동하도록 하므로 총 3가지를 push 해야 한다.

방향 그대로 push할 경우 cnt 그대로, 좌우로 push할 경우 cnt+1 을 해줘야 한다.

즉, 오른쪽 방향으로 이동할 경우에 거울을 발견한 경우 오른쪽방향으로 그대로 push할 때는 거울을 배치하지 않으므로 cnt 그대로, 위아래방향으로 push할 때는 거울을 배치하므로 cnt+1을 해줘서 push한다.

(3) 다음 구역에서의 방문처리를 해준다. (이때, 방문처리는 cnt+1으로 설정해둠) 

 

4. 그 외의 지점인 경우 => direction에 의존하여 3번과 동일하게 구현하였으나 방문된 경우에 접근하는 경우를 다음과 같이 처리하였다.

 

(1) 빛이 그대로 통과할 수 있는 '.' 구역은 상관없이 Queue에 push

(2) 거울을 발견할 경우 현재까지 거울을 배치한 갯수가 방문되어 있는 거울의 배치 수보다 작은 경우 Queue에 push하고 방문처리를 현재 cnt+1 값으로 수정해준다.

(3) 그외에 도착지점을 발견할 경우에 result=min(result, cnt) 를 해줘서 가장 배치를 적게한 수를 저장하도록 한다.

 


구현에 있어서 놓쳤던 점

 

92% 에서 실패가 떠서 질문게시판에 있는 반례들을 돌리다가 다음과 같은 반례를 발견하였다.

 

3
#!.
!!.
*#.

 

start 위치를 (0, 0) 이라고 둘 경우 : (0, 0) => (0, 1) 거울 배치 => (1, 1) => (2, 1) , 총 1번

start 위치를 (2, 1) 이라고 둘 경우 : (2, 1) => (1, 1) 거울 배치 => (1, 0) 거울 배치 => (0, 0) , 총 2번

 

이때 start 위치와 end 위치가 한개가 아닌 2개이며 이를 캐치하지 못해서 통과하지 못하였다.

 

풀이 code

 

#define _CRT_SECURE_NO_WARNINGS
#include <string>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <time.h>
#define INF 100000000
#define endl '\n'

using namespace std;

char arr[50][50];
int dx[4] = { -1,1,0,0 };
int dy[4] = { 0,0,-1,1 };
int visited[50][50];
int n, firstX = -1, firstY, endX, endY;
int result = INF;

class Light {
public:
	int x, y, direction;
	Light(int x, int y, int direction) {
		this->x = x;
		this->y = y;
		this->direction = direction;
	}
};

void input() {
	cin >> n;
	
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> arr[i][j];
			if (arr[i][j] == '#') {
				if (firstX == -1) firstX = i, firstY = j;
				else endX = i, endY = j;
			}
		}
	}
}

void solve(int firstX,int firstY,int endX,int endY) {
	queue<pair<Light,int>> q;
	q.push({ { firstX,firstY,-1 },0 });
	visited[firstX][firstY] = 1;

	while (!q.empty()) {
		int x = q.front().first.x;
		int y = q.front().first.y;
		int direction = q.front().first.direction;
		int cnt = q.front().second;
		q.pop();

		if (direction == -1) {
			for (int i = 0; i < 4; i++) {
				int nextX = x + dx[i];
				int nextY = y + dy[i];
				
				if (nextX >= 0 && nextX < n && nextY >= 0 && nextY < n) {
					if (arr[nextX][nextY] == '.') {
						q.push({ {nextX,nextY,i},cnt });
					}
					else if (arr[nextX][nextY] == '!') {
						if (i == 0 || i == 1) {
							q.push({ {nextX,nextY,i},cnt });
							q.push({ {nextX,nextY,2},cnt + 1 });
							q.push({ {nextX,nextY,3},cnt + 1 });
						}
						else {
							q.push({ {nextX,nextY,i},cnt });
							q.push({ {nextX,nextY,0},cnt + 1 });
							q.push({ {nextX,nextY,1},cnt + 1 });
						}
					}
					else if (nextX == endX && nextY == endY) {
						result = min(result, cnt);
					}
					visited[nextX][nextY] = cnt + 1;
				}
			}
		}
		else {
			int nextX = x + dx[direction];
			int nextY = y + dy[direction];
			
			if (nextX >= 0 && nextX < n && nextY >= 0 && nextY < n) {
				if (!visited[nextX][nextY]) {
					if (arr[nextX][nextY] == '.') {
						q.push({ {nextX,nextY,direction},cnt });
					}
					else if (arr[nextX][nextY] == '!') {
						if (direction == 0 || direction == 1) {
							q.push({ {nextX,nextY,direction},cnt });
							q.push({ {nextX,nextY,2},cnt + 1 });
							q.push({ {nextX,nextY,3},cnt + 1 });
						}
						else {
							q.push({ {nextX,nextY,direction},cnt });
							q.push({ {nextX,nextY,0},cnt + 1 });
							q.push({ {nextX,nextY,1},cnt + 1 });
						}
					}
					else if (nextX == endX && nextY == endY) {
						result = min(result, cnt);
					}
					visited[nextX][nextY] = cnt + 1;
				}
				else {
					if (arr[nextX][nextY] == '.') {
						q.push({ {nextX,nextY,direction},cnt });
						visited[nextX][nextY] = cnt + 1;
					}
					else {
						if (cnt < visited[nextX][nextY] - 1) {
							if (arr[nextX][nextY] == '!') {
								if (direction == 0 || direction == 1) {
									q.push({ {nextX,nextY,direction},cnt });
									q.push({ {nextX,nextY,2},cnt + 1 });
									q.push({ {nextX,nextY,3},cnt + 1 });
								}
								else {
									q.push({ {nextX,nextY,direction},cnt });
									q.push({ {nextX,nextY,0},cnt + 1 });
									q.push({ {nextX,nextY,1},cnt + 1 });
								}
							}
							else if (nextX == endX && nextY == endY) {
								result = min(result, cnt);
							}
							visited[nextX][nextY] = cnt + 1;
						}
					}
				}
			}
		}
	}
	return;
}

void init() {
	for (int i = 0; i < 50; i++) {
		for (int j = 0; j < 50; j++) {
			visited[i][j] = 0;
		}
	}
}

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

	input();
	solve(firstX,firstY,endX,endY);
	init();
	solve(endX, endY, firstX, firstY);
	cout << result;

	return 0;
}

'백준 > BFS, DFS' 카테고리의 다른 글

[백준 15684] 사다리 조작  (0) 2021.09.05
[백준 2146] 다리 만들기  (0) 2021.07.19
[백준 16947] 서울 지하철 2호선  (0) 2021.07.19
[백준 19538] 루머  (0) 2021.07.17
[백준 16929] Two Dots  (0) 2021.07.07
Comments