https://www.acmicpc.net/problem/14940
14940번: 쉬운 최단거리
지도의 크기 n과 m이 주어진다. n은 세로의 크기, m은 가로의 크기다.(2 ≤ n ≤ 1000, 2 ≤ m ≤ 1000) 다음 n개의 줄에 m개의 숫자가 주어진다. 0은 갈 수 없는 땅이고 1은 갈 수 있는 땅, 2는 목표지점이
www.acmicpc.net
걸린 시간 : 34분 33초
알고리즘
최단 거리 알고리즘 중 어떤 알고리즘?
최단 거리를 구할 수 있는 알고리즘 중 4가지를 살펴보자.
어떤 한 시작점에서 출발할 경우 | 모든 시작점을 다 고려할 경우 | |
가중치가 없는 경우 | BFS 알고리즘 | BFS or 플로이드 알고리즘 |
가중치가 있는 경우 | 다익스트라 알고리즘 | 플로이드 알고리즘 |
이렇게 4가지를 생각하면 어떤 문제에서 어떤 알고리즘을 써야할지 쉬울 것이다.
이 문제는 주변 칸까지의 거리가 모두 1이므로 가중치가 없다.
또한 도착점이 있지만, 역으로 생각해 도착점에서 모든 정점까지 거리를 구해도 되므로 한 시작점에서 시작한다고 생각해도 좋다.
따라서 BFS 알고리즘을 쓰자.
Pseudo Code
BFS의 대략적인 Pseudo Code는 다음과 같다.
board, dist, queue 선언 및 입력; int di[], dj[] 선언; dist배열을 모두 -1로 fill; // 1. 시작점 처리 queue에 시작노드 삽입; 시작노드 dist를 0으로; while (!q.empty()) { // 2. 현재 노드 처리 int ci, cj = q.top(); q.pop(); for (int k = 0; k < 방향 가짓수; k++) { // 3. 다음 노드 처리 int ni, nj = ci + di[k], cj + dj[k]; // 4. 방문할 것인지 if (ni와 nj가 범위안에 없다 || 갈 수 없는 곳(벽)이다 || 방문했다) continue; //여기서 방문했는지를 dist[ni][nj]가 -1인지로 체크 // 5. 방문 처리 큐에 nx, ny 삽입; dist[nx][ny] 최신화; } }
하지만, 이 문제의 끝 조건때문에 이와 같은 코드를 사용할 수 없다. 즉, dist 배열로 방문체크를 할 수 없다.
vis 배열을 따로 만들어 방문체크를 해야 한다.
board, dist, visited, queue 선언 및 입력; int di[], dj[] 선언; // 1. 시작점 처리 queue에 시작노드 삽입; 시작노드 visited 체크; while (!q.empty()) { // 2. 현재 노드 처리 int ci, cj = q.top(); q.pop(); for (int k = 0; k < 방향 가짓수; k++) { // 3. 다음 노드 처리 int ni, nj = ci + di[k], cj + dj[k]; // 4. 방문할 것인지 if (ni와 nj가 범위안에 없다 || 갈 수 없는 곳(벽)이다 || 방문했다) continue; // 5. 방문 처리 visited에 [ni][nj] 방문처리; 큐에 nx, ny 삽입; dist[nx][ny] 최신화; } }
이런 코드는 굉장히 자주 나오기 때문에 툭 치면 나올 정도로 외운다.
위처럼 dist배열만을 사용할 땐 방문처리할 때 2가지 일(큐 삽입, 거리 최신화)을 하고, vis배열까지 사용할 땐 방문처리할 때 3가지 일(큐 삽입, 거리 최신화, 방문처리)을 한다.
맨 처음에 설정할 때는 반대로 dist배열만을 사용할 땐 3가지 일(dist배열을 -1로 fill, 시작점 큐 삽입, 시작점 dist를 0으로)을 하고, vis배열까지 사용할 땐 2가지 일(시작점 큐 삽입, 시작점 방문처리)만을 한다.
정답 코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.LinkedList; import java.util.Queue; import java.util.StringTokenizer; public class BOJ14940 { static int n, m; static int[][] board = new int[1001][1001]; static int[][] dist = new int[1001][1001]; static boolean[][] vis = new boolean[1001][1001]; static int[] di = {-1, 0, 0, 1}; static int[] dj = {0, -1, 1, 0}; static Queue<Pos> q = new LinkedList<>(); public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] input = br.readLine().split(" "); n = Integer.parseInt(input[0]); m = Integer.parseInt(input[1]); Pos startPos = null; for (int i = 0; i < n; i++) { StringTokenizer st = new StringTokenizer(br.readLine()); for (int j = 0; j < m; j++) { board[i][j] = Integer.parseInt(st.nextToken()); if (board[i][j] == 2) { startPos = new Pos(i, j); } } } vis[startPos.i][startPos.j] = true; q.offer(startPos); while (!q.isEmpty()) { Pos cur = q.poll(); for (int k = 0; k < 4; k++) { Pos next = new Pos(cur.i + di[k], cur.j + dj[k]); if (next.i < 0 || next.i >= n || next.j < 0 || next.j >= m || board[next.i][next.j] == 0 || vis[next.i][next.j]) continue; q.offer(next); vis[next.i][next.j] = true; dist[next.i][next.j] = dist[cur.i][cur.j] + 1; } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (board[i][j] == 1 && dist[i][j] == 0) { System.out.print(-1 + " "); } else { System.out.print(dist[i][j] + " "); } } System.out.println(); } } static class Pos { int i, j; Pos(int i, int j) { this.i = i; this.j = j; } } }
'Baekjoon Online Judge' 카테고리의 다른 글
[BOJ] 2805 : 나무 자르기 (C++) (1) | 2023.12.26 |
---|---|
[BOJ] 9019 : DSLR (Java) (0) | 2023.11.09 |
[BOJ] 2630 : 색종이 만들기 (Java) with 분할 정복 (1) | 2023.11.09 |
[BOJ] 1927 : 최소 힙 (Java) (0) | 2023.11.02 |
[BOJ] 11444 : 피보나치 수 6 (Java) (0) | 2023.11.02 |