Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 프로그래밍 언어
- 플로이드-워셜
- 항해99
- 코테공부
- 갭체크
- 프로그래머스
- 코드트리
- 운영체제
- 연결 리스트
- 파이썬
- 자바스크립트
- 코딩테스트사이트추천
- C
- 알고리즘
- 자료구조
- 데이터베이스
- 오블완
- til
- 티스토리챌린지
- 개발자루틴
- 코딩테스트준비
- 인접 행렬
- Java
- 코딩테스트
- 1일1코테
- 99클럽
- #코드트리 #코딩테스트 #코테공부 #백트래킹 #알고리즘 기초
- 자바
- 개발자취업
- 웹
Archives
- Today
- Total
와드의 블로그
3197번: 백조의 호수 본문
문제
두 마리의 백조가 호수에 살고 있습니다. 호수는 행 R, 열 C 크기의 직사각형 모양이며, 물('.')과 빙판('X'), 그리고 백조('L')로 이루어져 있습니다. 매일 빙판은 물과 닿아있는 부분이 녹아서 물로 변합니다. 백조는 오직 물을 따라서 상하좌우로만 이동할 수 있습니다. 며칠이 지나야 두 백조가 서로 만날 수 있는지 구하는 프로그램을 작성하는 문제입니다.
- 입력: 첫째 줄에 R과 C가 주어집니다. (1 ≤ R, C ≤ 1,500) 둘째 줄부터 R개의 줄에 호수의 상태가 주어집니다.
- 출력: 첫째 줄에 며칠이 지나야 두 백조가 만날 수 있는지 출력합니다.
풀이: 2개의 큐(Queue)를 활용한 이어 달리기 BFS 최적화
이 문제의 맵 최대 크기는 1,500 × 1,500입니다. 만약 매일 얼음을 녹이고, 백조가 만날 수 있는지 매번 출발점부터 새로 BFS를 수행한다면 시간 초과가 발생합니다. 이를 해결하기 위해 물과 백조의 탐색 상태를 기억해 두고, 다음 날에는 이전 날에 막혔던 지점(빙판)부터 이어서 탐색하는 방식을 사용해야 합니다.
- 초기화 과정:
- 입력을 받으며 빙판이 아닌 곳(물 .과 백조 L)의 위치는 모두 얼음을 녹이는 주체가 되므로 waterQ에 넣습니다.
- 백조(L)를 만났을 때, 두 마리의 백조 중 첫 번째 백조만 출발점으로 삼기 위해 swanQ.isEmpty() 조건을 확인하고 큐(swanQ)에 삽입 및 방문 처리(visited)를 마칩니다.
- 백조 이동 (check 메서드):
- swanQ에는 현재 물이라서 이동 가능한 경로들이 들어있습니다. 이 경로들을 탐색하며 상하좌우로 이동합니다.
- 핵심 로직: 이동할 다음 칸이 물이면 계속해서 swanQ에 넣고 탐색하지만, 빙판('X')을 만나면 내일 녹을 예정이므로 nextSwanQ에 보관해 둡니다. 그리고 방문 처리를 하여 중복 탐색을 막습니다.
- 다른 백조('L')를 만나면 즉시 true를 반환합니다.
- 얼음 녹이기 (melt 메서드):
- waterQ에 들어있는 물의 위치에서 상하좌우를 탐색합니다.
- 인접한 칸에 빙판('X')이 있다면 녹는 표시로 바꾸고, 내일 이 자리 주변의 빙판이 또 녹아야 하므로 해당 위치를 nextWaterQ에 넣어둡니다.
- 상태 전이:
- 하루의 시뮬레이션이 끝난 뒤, 백조와 물의 탐색 큐를 다음 날 탐색해야 할 큐(nextSwanQ, nextWaterQ)로 교체합니다. 이를 통해 O(R * C) 시간 복잡도로 빠르게 정답을 찾을 수 있습니다.
코드
import java.util.*;
import java.io.*;
public class Main {
static class Node {
int y, x;
Node(int y, int x) {
this.y = y;
this.x = x;
}
}
static int n, m;
static char[][] a;
static boolean[][] visited;
static Queue<Node> waterQ = new LinkedList<>();
static Queue<Node> swanQ = new LinkedList<>();
static Queue<Node> nextWaterQ;
static Queue<Node> nextSwanQ;
static int[] dy = {-1, 0, 1, 0};
static int[] dx = {0, 1, 0, -1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
a = new char[n][m];
visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
String s = br.readLine();
for (int j = 0; j < m; j++) {
a[i][j] = s.charAt(j);
// 물이거나 백조인 경우(즉, 빙판이 아닌 경우) 얼음을 녹이기 위해 waterQ에 추가
if (a[i][j] != 'X') {
waterQ.add(new Node(i, j));
}
// 두 마리의 백조 중 첫 번째로 발견된 백조만 탐색 시작점으로 큐에 삽입
if (a[i][j] == 'L' && swanQ.isEmpty()) {
swanQ.add(new Node(i, j));
visited[i][j] = true;
}
}
}
int ans = 0;
while (true) {
nextWaterQ = new LinkedList<>();
nextSwanQ = new LinkedList<>();
// 백조가 서로 만났는지 확인
if (check()) {
break;
}
// 얼음 녹이기
melt();
// 큐 교체 (내일의 탐색을 위해)
swanQ = nextSwanQ;
waterQ = nextWaterQ;
ans++;
}
bw.write(ans + "");
bw.flush();
}
// 백조가 물을 따라 이동하는 BFS 탐색
static boolean check() {
while (!swanQ.isEmpty()) {
Node node = swanQ.poll();
for (int i = 0; i < 4; i++) {
int ny = node.y + dy[i];
int nx = node.x + dx[i];
if (ny < 0 || nx < 0 || ny >= n || nx >= m || visited[ny][nx])
continue;
// 다른 백조를 만난 경우 탐색 종료
if (a[ny][nx] == 'L') {
return true;
}
// 빙판을 만난 경우 내일 탐색하기 위해 nextSwanQ에 추가
else if (a[ny][nx] == 'X') {
nextSwanQ.add(new Node(ny, nx));
}
// 물인 경우 계속 이동 가능하므로 swanQ에 추가
else {
swanQ.add(new Node(ny, nx));
}
visited[ny][nx] = true;
}
}
return false;
}
// 물과 인접한 빙판을 녹이는 BFS 탐색
static void melt() {
while (!waterQ.isEmpty()) {
Node node = waterQ.poll();
for (int i = 0; i < 4; i++) {
int ny = node.y + dy[i];
int nx = node.x + dx[i];
if (ny < 0 || nx < 0 || ny >= n || nx >= m) {
continue;
}
// 인접한 칸이 빙판이면 물로 바꾸고 내일 탐색할 waterQ에 추가
if (a[ny][nx] == 'X') {
a[ny][nx] = '*';
nextWaterQ.add(new Node(ny, nx));
}
}
}
}
}
알고리즘 분류
그래프 이론 (Graph Theory), 그래프 탐색 (Graph Traversal), 너비 우선 탐색 (BFS)
'PS > B.O.J' 카테고리의 다른 글
| 11723번: 집합 (0) | 2026.05.01 |
|---|---|
| 10971번: 외판원 순회 2 (0) | 2026.04.30 |
| 10972번: 다음 순열 (0) | 2026.04.30 |
| 1248번: Guess (1) | 2026.04.30 |
| 15661번: 링크와 스타트 (0) | 2026.04.29 |