ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 2151번 거울설치
    문제 풀이 2020. 7. 17. 20:45

    2151 거울 설치


    문제


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

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

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

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

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


    입력


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


    출력


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



    풀이)

    문제 이해가 되지 않아서 다른 분의 풀이를 참고한 문제이다.


    거울 빛 반사부분이 특히 이해가 되지 않았는데 알고보니 이러한 말이였다.


    거울 설치 시 45도 기울어진 방향으로 설치하여 빛을 반사한다

    = 빛이 왔던 방향의 수직방향으로 바뀐다.


    (예) 빛이 오른쪽으로 가는 방향이었다면 -> 빛은 위쪽 혹은 아래쪽으로 방향 바뀜

         빛이 아래쪽으로 가는 방향이었다면 -> 빛은 왼쪽 혹은 오른쪽으로 방향 바뀜


    이 성질과 빛이 처음에 상하좌우 모두 퍼질 수 있다는 점을 고려해

    BFS로 각 위치 각 방향일 때의 최소 거울 개수를 구할 수 있다.


    참고사항

    1. 첫번째 문을 빛의 출발지, 두번째 문을 빛의 도착지라고 해준다.

       빛이 출발지에서 도착지에 도달해야 문끼리 서로 보일 수 있다는 뜻이다.

    2. 첫번째 문(출발지)에서 빛이 출발할 때 4방향 모두 탐색을 진행해준다.

    3. 중복되는 방문 처리 위해서 3중 배열을 사용해준다. 

       방문 위치 체크, 거울 설치 개수를 저장 : visited[y][x][상/하/좌/우]


       int visited[i][j][k] = (i,j)위치에서 방향이 k일때의 지금까지 설치한 최소 거울 개수


       + 배열의 초기값은 최대 값으로 초기화해둔다.

       + visited[출발지 y][출발지 x][상/하/좌/우] = 0으로 둔다. (출발지에서는 거울 개수 0이므로)


    4. 탐색하다가

      4.1 '.'을 만났을 경우 : 빛이 통과할 수 있는 지점. 그대로 탐색 진행

      4.2 '!'을 만났을 경우 : 거울을 설치할 수 있는 지점.

      거울을 설치할 경우와 설치 안 할 경우를 모두 탐색 진행

      (설치할 경우에는 왔던 방향과 수직인 방향으로 빛의 방향을 바꾸고,

       거울 개수도 +1 해줘야 한다)

      4.3 '*'을 만났을 경우 : 빛이 통과할 수 없는 지점. 탐색 그만


    5. 두번째 문 즉 빛의 도착지에서 visited[][][상/하/좌/우] 4가지 값 중 최소 거울 개수를 출력하면 된다.

       (한 쪽문에서 다른 쪽문을 볼 수 없는 경우는 주어지지 않는다고 했음)


    코드)


    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
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    #include <stdio.h>
    #include <queue>
    using namespace std;
     
    #define INF 999999999
    int N;
    char map[50][50];
    int visited[50][50][4];
    pair<intint> start, dest;
    //상 0 하 1 좌 2 우 3
    int dy[4= { -1,1,0,0 };
    int dx[4= { 0,0,-1,1 };
     
    struct Info {
        int y, x, dir;//위치, 방향 저장하는 구조체
        Info() {}
        Info(int y, int x, int dir) {
            this->= y;
            this->= x;
            this->dir = dir;
        }
    };
     
    void bfs() {
        queue <Info> qu;
        int change_dir[2];////바뀐 방향값 저장
        //출발지에서 4방향 모두 빛 출발
        for (int i = 0; i < 4; i++) {
            visited[start.first][start.second][i] = 0;
            qu.push({ start.first,start.second,i });
        }
        
        while(!qu.empty()) {
            int y = qu.front().y;
            int x = qu.front().x;
            int dir = qu.front().dir;
            qu.pop();
     
            int ny = y + dy[dir];
            int nx = x + dx[dir];
            if (ny < 0 || ny >= N || nx < 0 || nx >= N || map[ny][nx] == '*'continue;
     
            if (map[ny][nx] == '.') {//빛이 통과할 수 있는 지점
                if (visited[ny][nx][dir] > visited[y][x][dir]) visited[ny][nx][dir] = visited[y][x][dir];
                qu.push({ ny,nx,dir });
            }
            else if (map[ny][nx] == '!') { //거울 설치 가능한 지점
                //거울 설치 x
                if (visited[ny][nx][dir] > visited[y][x][dir]) {
                    visited[ny][nx][dir] = visited[y][x][dir];
                    qu.push({ ny,nx,dir });
                }
                //거울 설치
                //바뀐 방향 값 확인
                if (dir == 0 || dir == 1) {//원래 방향이 상,하 이면 방향은 좌, 우로 바뀜
                    change_dir[0= 2;
                    change_dir[1= 3;
                } 
                else {
                    change_dir[0= 0;
                    change_dir[1= 1;
                } 
                
                for (int i = 0; i < 2; i++) {
                    if (visited[ny][nx][change_dir[i]] > visited[y][x][dir] + 1) {
                        visited[ny][nx][change_dir[i]] = visited[y][x][dir] + 1;
                        qu.push({ ny,nx,change_dir[i] });
                    }
                }
            }
            else {//도착지일 경우
                if(visited[ny][nx][dir] > visited[y][x][dir]) visited[ny][nx][dir] = visited[y][x][dir];
            }
     
        }
     
    }
     
    int main() {
        scanf("%d"&N);
        getchar();
        bool find = false;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                for (int k = 0; k < 4; k++) visited[i][j][k] = INF;//최대값으로 초기화
                scanf("%c"&map[i][j]);
                if (map[i][j] == '#') {
                    if (find) {//두번째 문 즉 도착지 발견
                        dest.first = i;
                        dest.second = j;
                    }
                    else {//첫번째 문 즉 출발지 발견
                        start.first = i;
                        start.second = j;
                        find = true;
                    }
                }
            }
            getchar();//공백처리
        }
        bfs();
        int result = INF;
        for (int i = 0; i < 4; i++) {
            if (result > visited[dest.first][dest.second][i]) result = visited[dest.first][dest.second][i];
        }
        printf("%d", result);
        return 0;
    }
    cs


    '문제 풀이' 카테고리의 다른 글

    [백준] 2745번 진법 변환, 11005번 진법 변환 2  (0) 2020.07.20
    [백준] 2344번 거울  (0) 2020.07.18
    [백준] 1016번 제곱 ㄴㄴ수  (0) 2020.07.16
    [백준] 13901번 로봇  (0) 2020.07.15
    [백준] 14620번 꽃길  (0) 2020.07.14

    댓글

Designed by Tistory.