Competition/Baekjoon

[백준] 2146번 다리만들기

bisi 2020. 3. 25. 12:34
문제 출처 

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

 

2146번: 다리 만들기

여러 섬으로 이루어진 나라가 있다. 이 나라의 대통령은 섬을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다. 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다는 생각을 하게 되었다. 그래서 그는, 생색내는 식으로 한 섬과 다른 섬을 잇는 다리 하나만을 만들기로 하였고, 그 또한 다리를 가장 짧게 하여 돈을 아끼려 하였다. 이 나라는 N×N크기의 이차원 평면상에 존재한다. 이 나라는 여러 섬으로 이루어져 있으며, 섬이란 동서남북

www.acmicpc.net

 

 

 

접근 방식 및 풀이

- 키워드는 간척사업을 통해 다리를 만들수 있는 최소거리, BFS 활용이다.

- 너무 어려워서 아래 블로그 내용 참고 했다.

https://dundung.tistory.com/33

 

백준 2146 다리만들기 Java

정답률 30퍼센트의 DFS/BFS문제이다. 머리가 안좋아서인지 내 기준에선 많이 어려운것 같다 ㅠ 이 문제를 푸는방법에는 여러가지가 있다고 하지만 난 간척방법을 택해서 이해하기로 했다. 처음에도 간척하는 식으..

dundung.tistory.com

 

 

 

 

 

소스 코드 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

class Dot{
    int x ;
    int y ;

    public Dot(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

public class Main {
    public static final int[] dx ={0,0,-1,1};
    public static final int[] dy ={1,-1,0,0};
    
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        int[][] a = new int[n][n]; // 입력 받은 배열
        int[][] d = new int[n][n]; // 섬간의 거리 측정
        int[][] g = new int[n][n]; // 섬 그룹 번호매기기

        for (int i = 0; i < n; i++) {
            for (int j = 0; j <n ; j++) {
                a[i][j] = sc.nextInt();
            }
        }

        int count =0;
        /*섬 번호 매기기*/
        for (int i = 0; i <n ; i++) {
            for (int j = 0; j <n ; j++) {
                if(a[i][j] ==1 && g[i][j] == 0){
                    Queue<Dot> queue = new LinkedList<Dot>();
                    g[i][j] = ++count;
                    queue.add(new Dot(i,j));
                    while(!queue.isEmpty()){
                        Dot p = queue.remove();
                        int x = p.x;
                        int y = p.y;
                        for (int k = 0; k <4 ; k++) {
                            int nx = x + dx[k];
                            int ny = y + dy[k];
                            if(0<=nx && nx<n && 0<=ny && ny<n){
                                if(a[nx][ny] ==1 && g[nx][ny] == 0){
                                    queue.add(new Dot(nx,ny));
                                    g[nx][ny]=count;
                                }
                            }

                        }
                    }

                }
            }

        }

        Queue<Dot> queue = new LinkedList<Dot>();
        /*거리재기위한 사전 단계(섬(0)과 육지(-1) 구분)*/
        for (int i = 0; i <n ; i++) {
            for (int j = 0; j <n ; j++) {
                d[i][j] = -1;//섬이 아닌곳을 체크 하기 위해 -1로표시
                if(a[i][j] == 1){// 섬이기 때문에 큐에 넣고 0으로 바꾸자
                    queue.add(new Dot(i,j));
                    d[i][j]=0;
                }
            }
        }
        /*위에서 섬만 모아 놓은 큐를 활용하여 거리 측정 */
        while (!queue.isEmpty()){
            Dot p = queue.remove();
            int x = p.x;
            int y = p.y;
            for (int i = 0; i <4 ; i++) {
                int nx= x+dx[i];
                int ny= y+dy[i];
                if(0<=nx && nx<n && 0<=ny && ny<n){// 배열에 벗어나지 않는 범위에서
                    if(d[nx][ny] == -1){//섬 기준으로 상하좌우가 섬이 아닌곳이 거리 측정해야하는 곳임.
                        d[nx][ny] = d[x][y] +1;// 섬이 아닌곳으로 들어와서 d[][]에 임시로 만들어 놓았던 것에 +1, 즉, 0으로 만든다.
                        g[nx][ny] = g[x][y];// 섬의 영역 표시한 숫자로도 적어준다.
                        queue.add(new Dot(nx, ny));//bfs. 섬아닌 곳에 거리 측정해준 값들 모아두고 이따가 계산할꺼임.
                    }
                }
            }
        }
        /*마지막 !! d배열을 통해 거리를 계산하여 최솟값 구하는 곳 */
        int ans = -1;
        for (int i = 0; i <n ; i++) {
            for (int j = 0; j <n ; j++) {
                for (int k = 0; k <4 ; k++) {
                    // 상하좌우 찍으면서, 본인자리의 값이랑 비교하는 값이랑 다르면 거리를 계산해야하는 지점임.
                    int x = i + dx[k];
                    int y = j + dy[k];
                    if(0<=x && x<n && 0<=y && y<n){
                        if(g[i][j] != g[x][y]){
                            // 최솟값 ans이 -1이거나, 최소값보다 더 작은 경우가 나올 경우 바꿔준다.
                           if(ans == -1 || ans > d[i][j] + d[x][y]){
                               ans = d[i][j] + d[x][y];
                           }
                        }
                    }
                }
            }
        }
        System.out.println(ans);
    }
}

 

 

 

 

결과 

 

 

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

[백준] 2331번 반복수열  (0) 2020.03.25
[백준] 1654번 랜선 자르기  (0) 2020.03.24
[백준] 10451번 순열사이클  (0) 2020.03.24