# 거울 설치 - BOJ

거울 설치 - BOJ

# 문제

채영이는 거울을 들여다보는 것을 참 좋아한다. 그래서 집 곳곳에 거울을 설치해두고 집 안을 돌아다닐 때마다 거울을 보곤 한다.

채영이는 새 해를 맞이하여 이사를 하게 되었는데, 거울을 좋아하는 그녀의 성격 때문에 새 집에도 거울을 매달만한 위치가 여러 곳 있다. 또한 채영이네 새 집에는 문이 두 개 있는데, 채영이는 거울을 잘 설치하여 장난을 치고 싶어졌다. 즉, 한 쪽 문에서 다른 쪽 문을 볼 수 있도록 거울을 설치하고 싶어졌다.

채영이네 집에 대한 정보가 주어졌을 때, 한 쪽 문에서 다른 쪽 문을 볼 수 있도록 하기 위해 설치해야 하는 거울의 최소 개수를 구하는 프로그램을 작성하시오.

거울을 설치할 때에는 45도 기울어진 대각선 방향으로 설치해야 한다. 또한 모든 거울은 양면 거울이기 때문에 양 쪽 모두에서 반사가 일어날 수 있다. 채영이는 거울을 매우 많이 가지고 있어서 거울이 부족한 경우는 없다고 하자.

거울을 어떻게 설치해도 한 쪽 문에서 다른 쪽 문을 볼 수 없는 경우는 주어지지 않는다.

[입력]

첫째 줄에 집의 크기 N (2 ≤ N ≤ 50)이 주어진다. 다음 N개의 줄에는 N개의 문자로 집에 대한 정보가 주어진다. ‘#’는 문이 설치된 곳으로 항상 두 곳이며, ‘.’은 아무 것도 없는 것으로 빛은 이 곳을 통과한다. ‘!’은 거울을 설치할 수 있는 위치를 나타내고, ‘*’은 빛이 통과할 수 없는 벽을 나타낸다.

[출력]

첫째 줄에 설치해야 할 거울의 최소 개수를 출력한다.

# 풀이

  • BFS로 접근
  • 거울이 45도 각도로 있다고 했으므로 거울에 대각선 방향으로 들어온다면 입사각 그대로 반사되어 나갈 것이므로 제외. 동서남북 4방향으로만 탐색하면 된다.
  • '#'(문) 의 위치에서부터 시작해서 벽이 아닌 곳을 큐에 집어넣고 탐색. 이때 큐에 들어가는 것은 다음 좌표거울의 개수, 방향 이다.
  • 방문하지 않았거나, 전에 탐색했을 때보다 거울의 개수가 작다면, 거울의 개수를 갱신하며 탐색
  • 거울에 상하로 들어왔다면 좌우 방향으로 나갈 수 있을 것이고, 좌우로 들어왔다면 상하 방향으로 나갈 수 있을 것이다.
  • 거울 설치가 최소로 되는 것을 찾으라고 했으므로 거울을 만났을 때 부딪히지 않고 지나치는 경우를 추가해 주어야 한다. 이 부분을 생각하지 못하여 WA가 떴었다.
from collections import deque

dy = [-1,1,0,0]
dx = [0,0,-1,1]

N = int(input())
house = [list(input()) for _ in range(N)]
door, mirror = [], []
ret = float('inf')

for i in range(N):
    for j in range(N):
        if house[i][j] == '#':
            door.append([i, j])

y, x = door[0]
desy, desx = door[1]
visit = {}
q = deque()

for way in range(4):
    nx = x + dx[way]
    ny = y + dy[way]
    if 0 > nx or 0 > ny or ny >= N or nx >= N:
        continue
    if house[ny][nx] != '*':
        q.append((nx, ny, 0, way)) # 좌표, cnt, 방향

while q:
    x, y, cnt, way = q.popleft()
    if 0 > x or 0 > y or y >= N or x >= N:
        continue
    if visit.get((x, y, way)) == None or visit[(x, y, way)] > cnt: # 방문하지 않았거나, 탐색했던 것보다 거울 개수가 작다면 갱신
        visit[(x, y, way)] = cnt
        nx = x + dx[way]
        ny = y + dy[way]
        if x == desx and y == desy:
            ret = min(cnt, ret)
        elif house[y][x] == '.':
            q.append((nx, ny, cnt, way))
        elif house[y][x] == '!':
            q.append((nx, ny, cnt, way)) # 거울이 해당 자리에 있더라도 지나치는 경우
            if way == 0 or way == 1:
                q.append((x + dx[2], y + dy[2], cnt + 1, 2))
                q.append((x + dx[3], y + dy[3], cnt + 1, 3))
            else:
                q.append((x + dx[0], y + dy[0], cnt + 1, 0))
                q.append((x + dx[1], y + dy[1], cnt + 1, 1))
print(ret)