CVillain

[백준] 5022 - 연결 본문

Algorithm/Baekjoon

[백준] 5022 - 연결

CVillain 2021. 11. 22. 20:48

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

 

5022번: 연결

A1과 A2, 그리고 B1과 B2를 연결하는데 필요한 전선의 길이의 최솟값을 출력한다. 만약, 불가능한 경우에는 "IMPOSSIBLE"을 출력한다.

www.acmicpc.net

 

문제

 

전기 회로에서 두 점을 전선으로 이을 때, 길이는 짧을 수록 좋다.

크기가 N×M인 비어있는 회로판에서 두 점 A1과 A2, 그리고 B1와 B2를 전선을 이용해서 이으려고 한다. 전선은 항상 그리드의 수직, 수평선 위에 있어야 한다. 또, 두 직선은 접하면 안 된다. 이 경우에 필요한 전선의 길이의 최솟값을 구하는 프로그램을 작성하시오. 전선은 회로판 바깥으로 나갈 수 없다.

 

입력

 

첫째 줄에 회로판의 크기 N과 M이 주어진다. (2 ≤ N, M ≤ 100)

다음 네 줄에는 A1, A2, B1, B2의 좌표가 주어진다. 점의 좌표는 두 정수의 쌍으로 이루어져 있고, 첫 번째 좌표는 0 이상 N 이하이며 두 번째 좌표는 0 이상 M 이하이다. 어떤 점도 같은 위치에 있지 않다.

 

출력

 

A1과 A2, 그리고 B1과 B2를 연결하는데 필요한 전선의 길이의 최솟값을 출력한다. 만약, 불가능한 경우에는 "IMPOSSIBLE"을 출력한다.

 


풀이

 

너비 우선 탐색(BFS, Breadth First Search)의 응용 문제다.

 

두 전선이 간섭 없이 최단 거리로 연결되어야 한다. 그러기 위해선 둘 중 하나가 최단 거리로 연결되어야 한다. 결국,

1. A → B : A 전선이 먼저 최단 거리로 연결되고, B 전선을 연결한다.
2. B → A : B 전선이 먼저 최단 거리로 연결되고, A 전선을 연결한다.

*만약 두 경우 모두, 두 번째 연결하는 전선이 간섭이 생겨 연결할 수 없다면, IMPOSSIBLE를 출력한다.

결론적으로 총 4번의 BFS가 실행되어야 한다.

 

이번 문제도 앞의 과외맨 문제와 마찬가지로 path 배열을 이용해서 경로를 구했다.

위의 1의 경우에서 방문 표시를 할 visited 배열을 한 번 선언하고, A를 탐색한 후 path 배열의 정보를 따라 다시 visited 배열에 A의 경로를 입력해주었다. 이후 B를 탐색할 때, 앞의 visited 배열을 바로 사용해주면 하나의 케이스를 탐색할 수 있게 된다. *케이스 1에서 2로 넘어갈 때에는 visited 배열을 새로 만들어 준다.

 

채점하는데 계속 0~1%에서 틀리길래, 경우를 따져봤더니 처음 탐색을 할 때, 나머지 전선의 시작점과 끝점을 고려해주지 않았다. 예를 들어,

 

이 경우 IMPOSSIBLE이 출력되어야 하는데, A를 먼저 탐색할 때를 기준으로 왼쪽 B를 거쳐서 전선을 연결했다. 이처럼 탐색할 때, 또다른 전선의 시작점과 끝점을 방문 표시 해놓고 탐색을 하니까 PASS 할 수 있었다.

 

 

전체 코드

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

class Circuit {

    int index;

    public Circuit(int index) {
        this.index = index;
    }
}

public class Main {

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

    public static int n, m;
    public static int[][] A, B;
    public static boolean[][] visited;
    public static Circuit[][] map;
    public static Map<Integer,int[]> locations;

    public static void input() throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());

        locations = new HashMap<>();
        map = new Circuit[n+1][m+1];
        A = new int[2][2];
        B = new int[2][2];

        int index = 1;

        for(int i=0; i<2; i++) {
            st = new StringTokenizer(br.readLine(), " ");

            A[i][0] = Integer.parseInt(st.nextToken());
            A[i][1] = Integer.parseInt(st.nextToken());
        }
        for(int i=0; i<2; i++) {
            st = new StringTokenizer(br.readLine(), " ");

            B[i][0] = Integer.parseInt(st.nextToken());
            B[i][1] = Integer.parseInt(st.nextToken());
        }
        for(int i=0; i<=n; i++) {
            for(int j=0; j<=m; j++) {
                locations.put(index, new int[]{i, j});
                map[i][j] = new Circuit(index++);
            }
        }
    }

    public static int connect(int[][] cable, int[][] other) {

        Queue<int[]> q = new LinkedList<>();
        int[] path = new int[(n+1)*(m+1)+1];
        int[] src = cable[0];
        int[] dst = cable[1];
        boolean isConnected = false;

        q.offer(new int[]{src[0], src[1]});
        path[map[src[0]][src[1]].index] = 0;
        visited[src[0]][src[1]] = true;

        while(!q.isEmpty()) {
            int x = q.peek()[0];
            int y = q.peek()[1];
            q.poll();

            if(x == dst[0] && y == dst[1]) {
                isConnected = true;
                break;
            }

            for(int i=0; i<4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];

                if(nx < 0 || nx > n || ny < 0 || ny > m) continue;
                if(nx == other[0][0] && ny == other[0][1]) continue;
                if(nx == other[1][0] && ny == other[1][1]) continue;
                if(!visited[nx][ny]) {
                    visited[nx][ny] = true;
                    path[map[nx][ny].index] = map[x][y].index;
                    q.offer(new int[]{nx, ny});
                }
            }
        }

        if(!isConnected) return -1;

        visited = new boolean[n+1][m+1];
        int index = map[dst[0]][dst[1]].index;
        int ret = 0;

        visited[dst[0]][dst[1]] = true;
        while(path[index] != 0) {
            int[] p = locations.get(path[index]);
            visited[p[0]][p[1]] = true;
            index = path[index];
            ret++;
        }

        return ret;
    }

    public static void connection() {

        int case1 = 0, case2 = 0;

        visited = new boolean[n+1][m+1];
        int distance = connect(A, B);

        if(distance == -1) case1 = Integer.MAX_VALUE;
        else {
            case1 += distance;
            distance = connect(B, A);

            if(distance == -1) case1 = Integer.MAX_VALUE;
            else case1 += distance;
        }


        visited = new boolean[n+1][m+1];
        distance = connect(B, A);

        if(distance == -1) case2 = Integer.MAX_VALUE;
        else {
            case2 += distance;
            distance = connect(A, B);

            if(distance == -1) case2 = Integer.MAX_VALUE;
            else case2 += distance;
        }

        System.out.println(case1 == Integer.MAX_VALUE && case2 == Integer.MAX_VALUE ? "IMPOSSIBLE" : Math.min(case1, case2));
    }

    public static void main(String[] args) throws IOException {

        input();
        connection();
    }
}

 

 

 

 

'Algorithm > Baekjoon' 카테고리의 다른 글

[백준] 5213 - 과외맨  (0) 2021.11.20
[백준] 12094 - A와 B  (0) 2021.11.18
[백준] 2887 - 행성 터널  (0) 2021.11.16
Comments