문제 풀이

[백준] 2344번 거울

컴영 2020. 7. 18. 22:07

2344번 거울


문제


세로 N, 가로 M 크기의 상자가 있다. 이 상자 안에는 몇 개의 거울이 들어 있다. 상자를 위에서 봤을 때, 거울은 한 칸 안에 대각선 모양으로 들어있다고 한다. 또, 상자의 테두리를 따라서 칸마다 구멍이 뚫려 있다. 편의상 구멍은 왼쪽 위에 뚫려있는 것부터 시계 반대 방향으로 1, 2, …, 2N+2M 의 번호가 붙어 있다. 예를 들어 다음과 같은 경우를 보자.

이제 이 상자에 뚫려있는 구멍으로 빛을 쏜다고 생각해보자. 1번 구멍으로 쏠 경우에는 (1, 2)의 위치에 있는 거울에 반사되어 9번 구멍으로 빛이 가게 된다. 또, 2번 구멍으로 빛을 쏠 경우에는 (2, 2)의 위치에 있는 거울과 (1, 2)에 있는 거울에 차례로 반사되어 7번 구멍으로 빛이 나가게 된다.

이와 같이 상자의 모양이 주어졌을 때, 각 구멍으로 쏜 빛이 나가게 되는 구멍을 구하는 프로그램을 작성하시오.


입력


첫째 줄에 N, M (1 ≤ N, M ≤ 1,000)이 주어진다. 다음 N개의 줄에는 M개의 수로 상자의 모양이 주어진다. 거울이 있는 위치는 1로, 거울이 없는 위치는 0으로 주어진다. 거울은 / 모양으로만 놓일 수 있다고 하자.


출력


첫째 줄부터 차례로 1번 구멍으로 쏜 빛이 나가는 구멍의 번호, 2번 구멍으로 쏜 빛이 나가는 구멍의 번호, …, 2N+2M번 구멍으로 쏜 빛이 나가는 구멍의 번호를 출력한다.




풀이)

재귀 방법을 이용해 빛이 어떤 구멍으로 나가는 지 확인해준 문제이다.


1. 세로 N, 가로 M인 상자가 있다면 전체 map크기를 아래처럼 생각한다.

   (예시) N = 5, M =4 일경우

맵 크기는 (N+2 =7) * (M+2 = 6)



2. 구멍의 번호를 저장해준다. 

   (이 때, 거울의 위치와 1번 구멍을 햇갈리지 않기 위해 거울 있는 곳은 -1로 바꿔준다)

3. 각 1번 구멍부터 출발해 다른 구멍의 번호(1이상)가 나올 때까지 탐색해준다.

 3.1 거울을 만날 경우 방향을 바꾼 뒤 탐색

(방향은 항상 수직으로 바뀌며, 왼쪽 방향이였을 경우 위쪽 방향으로. 위쪽 방향이었을 경우 오른쪽 방향으로 바뀜.

 아래 그림처럼 바뀜)



 3.2 거울이 아닌 경우는 방향을 그대로 유지한 채 탐색



코드)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <stdio.h>
using namespace std;
 
int N, M;
int map[1005][1005];
int dy[4= { -1,1,0,0 };
int dx[4= { 0,0,-1,1 };
 
int change_dir(int d) {
    if (d == 0return 3;
    else if (d == 1return 2;
    else if (d == 2return 1;
    else return 0;
}
 
int dfs(int y, int x,int dir) {
    int ny = y + dy[dir];
    int nx = x + dx[dir];
    //다른 구멍으로 빛이 빠짐
    if (map[ny][nx] >= 1return map[ny][nx];
    else {
        //거울을 만나면
        if (map[ny][nx] == -1return dfs(ny, nx, change_dir(dir));
        else //거울 안만나면 계속 빛 방향 유지
            return dfs(ny, nx, dir);
    }
}
 
int main() {
    scanf("%d %d"&N, &M);
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            scanf("%d"&map[i][j]);
            if (map[i][j] == 1) map[i][j] = -1;
        }
    }
    //1. 구멍 번호 채우기
    //왼쪽면, 오른쪽면 구멍 번호
    for (int i = 1; i <= N; i++) {
        map[i][0= i;
        map[N + 1 - i][M + 1= N + M + i;
    }
    //아래면, 윗면 구멍 번호
    for (int i = 1; i <= M; i++) {
        map[N + 1][i] = N + i;
        map[0][M + 1 - i] = N * 2 + M + i;
    }
 
    //2. 구멍에서 빛 쏘기
    //1) 왼쪽면 구멍에서
    for (int i = 1; i <= N; i++) {
        printf("%d ", dfs(i, 03));
    }
    //2) 아랫면 구멍에서
    for (int i = 1; i <= M; i++) {
        printf("%d ", dfs(N+1, i, 0));
    }
    //3) 오른쪽면, 빛 방향 : 왼쪽
    for (int i = N; i >= 1; i--) {
        printf("%d ", dfs(i, M+12));
    }
    //4) 위쪽면, 빛 방향 : 아래
    for (int i = M; i >= 1; i--) {
        printf("%d ", dfs(0, i, 1));
    }
    return 0;
}
cs