developer-ellen
인간 디버거의 로그 찍기
developer-ellen
전체 방문자
오늘
어제
  • 분류 전체보기 (217)
    • 회고록 (0)
    • 취뽀 및 커리어 여정의 Stack (2)
      • SSAFY 7기 (2)
    • 프로그래밍공부 (24)
      • c++ (0)
      • JAVA (3)
      • Spring (5)
      • design pattern (3)
      • BackDB (1)
      • Servlet&JSP (3)
      • Vue (4)
      • JPA (4)
      • Infra (1)
      • Linux (0)
    • AI (3)
      • papers (3)
      • trend (0)
    • 프로젝트진행 (0)
      • 데이터베이스 (0)
      • 서버개발 (0)
      • 인공지능 (0)
      • 하루정리 (0)
    • 포트폴리오 (0)
    • 알고리즘 (158)
      • 알고리즘문풀 (155)
      • 알고리즘공부 (3)
    • 통계공부 (15)
      • 시계열분석 (15)
      • 회귀분석 (0)
    • CS (14)
      • 컴퓨터네트워크 (4)
      • 운영체제 (8)
      • 데이터베이스 (2)
    • 주저리주저리 (0)
      • 필사 (0)
    • 취업관련정보 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 카카오코테
  • MA모형
  • SW역량테스트파이썬
  • c++디자인패턴
  • 통계학
  • 삼성코테자바풀이
  • 삼성코테기출자바풀이
  • 운영체제인터럽트
  • 삼성코테파이썬풀이
  • BOJ파이썬풀이
  • 통계분석
  • 시계열분석
  • SW역량테스트파이썬풀이
  • Arima
  • 백준파이썬풀이
  • 시계열
  • 카카오코테java풀이
  • 데이터분석
  • ARIMA모형
  • 삼성코테파이썬준비
  • 삼성코테자바준비
  • 삼성코테준비
  • c++ 빌더 패턴
  • 삼성코테구현문제추천
  • 코테파이썬
  • 삼성코테파이썬
  • 삼성코테구현풀이
  • AR모형
  • 삼성코테자바꿀팁
  • 삼성코테기출

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
developer-ellen

인간 디버거의 로그 찍기

알고리즘/알고리즘문풀

BOJ - 다리 만들기 2146번 (JAVA)

2022. 9. 9. 23:18

❓ 문제 - 백준 다리 만들기 2146번 - JAVA 풀이법

 

출처

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

 

2146번: 다리 만들기

여러 섬으로 이루어진 나라가 있다. 이 나라의 대통령은 섬을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다. 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다

www.acmicpc.net

 

 

📝 문제해결법

1. 문제

  • N*N 크기의 이차원 평면상에 여러 개의 섬으로 이루어져 있는데 각 섬을 바다 위에 놓을 수 있다.
  • 두 대륙을 잇는 가장 짧은 다리의 길이를 구하여라.

 

2. 해결 방법

  • 우선 N의 크기가 (100이하의 자연수)이기 때문에 BFS나 DFS의 완전탐색 기법으로 이어진 섬을 분류하고 각 섬에서 다른 섬으로 다시 BFS나 DFS로 바다의 다리를 만들어가면서 다른 육지로 갈 수 있는 다리의 길이를 구한 뒤 최솟값을 갱신하면 된다.
  • 만약 완전탐색 기법으로 BFS를 두 번 이용하면 첫 번째 섬을 구분할 때 N*N, 두 번째 다리를 연결할 때 섬의 최대갯수(N)*N*N 정도여서 시간안에 통과 가능하다.
  • 두 번째 각 섬에서 바다에 다리를 놔서 다른 섬까지 이어지는 다리의 길이를 구할 때는 4방 탐색으로 바다일 경우 다리의 길이를 늘리고 만약 다른 섬이라면 다리가 끝나므로 지금까지 구한 다리의 길이를 갱신하도록 한다.
  • 하지만 여기서 주의할 점은, boolean visited의 방문처리로만 이 다리 길이를 구하면  밑의 경우처럼 이미 방문되었지만 다리길이가 최소가 아닌데, 다른 최소의 길이로 해당 지역을 방문하면 이미 방문처리 되었기 때문에 탐색을 멈춘다. 따라서 최소의 다리 길이를 구할 수 없게 된다.  
10
1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1

=> 여기서 답은 17이 나와야 함
  • 따라서 두 번째 BFS 내에서 방문에 대한 것을 int[][] visited 2차원 배열로 관리한다.
  • 그리고 만약 지나가려는데 바다라면 이미 방문하지 않은 경우나 현재 지금까지의 다리길이로 더 짧게 해당 지역에 다리를 건설할 수 있는 경우에만 q에 넣어 방문할 수 있도록 구현한다.
  • 밑의 코드는 위의 설명을 나타나는 부분이다.
if(visited[nx][ny] == -1 || visited[nx][ny] > visited[node.x][node.y]+1){
    visited[nx][ny] = visited[node.x][node.y]+1;
    q.add(new Node(nx, ny));
}

 

 

 

 

3. 느낀점

  • 구현 방법은 쉽게 떠올렸지만 시간초과랑 메모리 초과 둘 다 떠서 이틀동안 고민했던 것... 알고보니 시간초과는 dfs -> bfs로 바꾸고 방문처리에 대한 것을 boolean에서 int 2차원배열로 바꿔서 해결했다.
  • 근데 그 뒤에 메모리 초과가 떠서 처음에 방문처리 2차원 배열이 너무 많이 생성돼서 그런가 하면서 계속 고민했는데 알고보니 queue에 너무 많은 값들이 들어가서 그런 것.. 그리고 visited[nx][ny] > visited[node.x][node.y]로 잘못 코딩해서 그랬다..^^
  • 그래도 시초, 메초를 코드를 꾸준히 봐서 해결할 수 있어서 뿌듯하다.. 이제 이런 실수는 하지 말아야지!

 

 

💻 소스코드 (JAVA)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    public static int n;
    public static int s;
    public static int[][] map;
    public static int[][] check;
    public static int min_value;

    public static class Node {
        int x;
        int y;
        public Node(int x, int y){
            this.x = x;
            this.y = y;
        }
    }

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

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

        n = Integer.parseInt(br.readLine());
        s = 0;
        map = new int[n][n];
        check = new int[n][n];
        for(int i=0;i<n;i++){
            st = new StringTokenizer(br.readLine(), " ");
            for(int j=0;j<n;j++){
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        min_value = Integer.MAX_VALUE;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(check[i][j] == 0 && map[i][j] == 1){
                    bfs(i, j, ++s);
                }
            }
        }

        for(int i=1;i<=s;i++){
            bfs2(i);
        }

        System.out.println(min_value);
    }
	
    // 각 연결된 육지로 섬의 번호를 부여하는 bfs
    public static void bfs(int x, int y, int c){
        Queue<Node> q = new LinkedList<>();
        check[x][y] = c;
        q.add(new Node(x, y));
        while (!q.isEmpty()){
            Node node = q.poll();
            for(int d=0;d<4;d++){
                int nx = node.x + dx[d];
                int ny = node.y + dy[d];
                if(0 <= nx && nx < n && 0 <= ny && ny < n){
                    if(map[nx][ny] == 1){
                        if(check[nx][ny] == 0){
                            check[nx][ny] = c;
                            q.add(new Node(nx, ny));
                        }
                    }

                }
            }
        }
    }
	
    // 각 연결된 섬에서 다리를 놓는 bfs
    public static void bfs2(int c){
        Queue<Node> q = new LinkedList<>();
        int[][] visited = new int[n][n];
        for(int i=0;i<n;i++){
            Arrays.fill(visited[i], -1);
        }

        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(check[i][j] == c){
                    visited[i][j] = 0;
                    q.add(new Node(i, j));
                }
            }
        }

        while (!q.isEmpty()){
            Node node = q.poll();
            for(int d=0;d<4;d++){
                int nx = node.x + dx[d];
                int ny = node.y + dy[d];
                if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
				// 4방 탐색한 경우 중 바다인 경우 -> 다리를 놓아야함
                if(map[nx][ny] == 0){
                    if(visited[nx][ny] == -1 || visited[nx][ny] > visited[node.x][node.y]+1){
                        visited[nx][ny] = visited[node.x][node.y]+1;
                        q.add(new Node(nx, ny));
                    }
                } else if(check[nx][ny] != c){ // 4방 탐색했을 때 다른 섬일 경우 -> 다리를 끝내고 다리길이 갱신
                    min_value = Math.min(min_value, visited[node.x][node.y]);
                }

            }
        }
    }

}

'알고리즘 > 알고리즘문풀' 카테고리의 다른 글

BOJ - 네트워크 복구 2211번 (JAVA)  (0) 2022.09.18
BOJ - 우주신과의 교감 1774번 (JAVA)  (0) 2022.09.10
BOJ - 벽 부수고 이동하기4 16946번 (JAVA)  (0) 2022.09.04
BOJ - 정육면체 9029번 (JAVA)  (0) 2022.08.28
BOJ - 친구 네트워크 4195번 (JAVA)  (0) 2022.08.25
    '알고리즘/알고리즘문풀' 카테고리의 다른 글
    • BOJ - 네트워크 복구 2211번 (JAVA)
    • BOJ - 우주신과의 교감 1774번 (JAVA)
    • BOJ - 벽 부수고 이동하기4 16946번 (JAVA)
    • BOJ - 정육면체 9029번 (JAVA)
    developer-ellen
    developer-ellen

    티스토리툴바