Algorithm/백준 문제풀이

[백준] 6087 레이저 통신 - Java

너지살 2023. 9. 27. 16:21

 

문제 출저

https://www.acmicpc.net/problem/6087

 

6087번: 레이저 통신

크기가 1×1인 정사각형으로 나누어진 W×H 크기의 지도가 있다. 지도의 각 칸은 빈 칸이거나 벽이며, 두 칸은 'C'로 표시되어 있는 칸이다. 'C'로 표시되어 있는 두 칸을 레이저로 통신하기 위해서

www.acmicpc.net

 

 

문제 풀이

높이 h, 넓이 w 인 격자판이 주어집니다. 격자판 안에는 레이저를 이어야 하는 지점인 C 2개와 벽인 *, 레이저가 지나가는 . 으로 이루어져 있습니다. 이 때 거울을 설치하면 레이저의 방향을 90도 바꿀 수 있습니다. C끼리 레이저로 연결하기 위해 최소한의 거울 갯수를 구하는 것이 문제의 요구사항 입니다.

 

다익스트라 알고리즘으로 풀었습니다. 

int[h][w][4] dp 인 3차원 배열을 선언합니다. 이 배열은 4방향으로 들어온 최솟값을 저장하게 됩니다.

 

C 중 하나의 값을 탐색으로 진행합니다. 

BFS 방식을 사용했고 Queue 를 만들어 4방향을 탐색했습니다. 

이 때, 빛은 반대방향으로 꺾을 수 없으므로 반대 방향은 탐색에서 제외했습니다.

90도로 꺾을 때 마다 +1을 해주었습니다. 다음 지점을 탐색할 때 dp에 저장된 값과 비교하여 작은 경우 탐색을 진행합니다. 이 때, 작은 값은 dp에 저장하여 그 지점은 항상 최소값으로 유지되게 했습니다. 

 

 

소스 코드

package baekjoon.backjoon9.day27;

import java.util.*;
import java.lang.*;
import java.io.*;

/*
레이저 통신
https://www.acmicpc.net/problem/6087
 */

public class B6087 {

    static int w,h;
    static char[][] board;
    static int[] start;
    static int[] end;

    static int[][][] dp;
    static int INF = Integer.MAX_VALUE;

    static int[] dx = {1,0,-1,0};
    static int[] dy = {0,-1,0,1};


    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        StringTokenizer st = new StringTokenizer(br.readLine());

        w = Integer.parseInt(st.nextToken());
        h = Integer.parseInt(st.nextToken());

        board = new char[h][w];
        start = new int[2];
        end = new int[2];
        boolean flag = false;

        for(int i = 0; i < h; i++) {
            String str = br.readLine();
            for(int j = 0; j < w; j++) {
                board[i][j] = str.charAt(j);

                if(board[i][j] == 'C') {
                    if(flag == false) {
                        start[0] = i;
                        start[1] = j;
                        flag = true;
                    }
                    else {
                        end[0] = i;
                        end[1] = j;
                    }
                }
            }
        }

        dp = new int[h][w][4];
        for(int i = 0; i < h; i++) {
            for(int j = 0; j < w; j++) {
                Arrays.fill(dp[i][j], INF);
            }
        }

        Queue<dot> que = new LinkedList<>();
        for(int i = 0; i < 4; i++) {
            que.add(new dot(start[0], start[1], i, 0));
            dp[start[0]][start[1]][i] = 0;
        }



        while (!que.isEmpty()) {

            dot d = que.poll();

            for(int i = 0; i < 4; i++) {

                // 뒤로 쏘는 방향은 없다
                if(Math.abs(d.dir - i) == 2) {
                    continue;
                }

                int ny = d.y + dy[i];
                int nx = d.x + dx[i];

                if(check(ny,nx)) {

                    int newCount = d.count;

                    // 거울을 설치할 경우
                    if(Math.abs(d.dir - i) == 1 || Math.abs(d.dir - i) == 3) {
                        newCount += 1;
                    }

                    if(dp[ny][nx][i] > newCount) {
                        dp[ny][nx][i] = newCount;
                        que.add(new dot(ny, nx, i, newCount));
                    }

                }
            }
        }

        int answer = INF;
        for(int i = 0; i < 4; i++) {
            answer = Math.min(answer, dp[end[0]][end[1]][i]);
        }
        System.out.println(answer);



    }

    public static boolean check(int y, int x) {
        if(y >= 0 && y < h && x >= 0 && x < w && board[y][x] != '*') {
            return true;
        }
        else {
            return false;
        }
    }

    public static class dot {
        int y;
        int x;
        int dir;
        int count;

        dot(int y, int x, int dir, int count) {
            this.y = y;
            this.x = x;
            this.dir = dir;
            this.count = count;
        }
    }
}