시리즈: 알고리즘 (32개 글)
- 자바로 알고리즘 풀기
- [Java] 백준 10431 - 줄 세우기
- [Java & Node.js] 백준 9935 - 문자열 폭발
- [Node.js] 백준 22866 - 탑 보기
- [Java] 백준 4485 - 녹색 옷 입은 애가 젤다지?
- [Node.js] 백준 1283 - 단축키 지정
- [Java & Node.js] 백준 14469 - 소가 길을 건너간 이유 3
- [Java] 백준 8979 - 올림픽
- [Node.js] 백준 22866 - 탑 보기
- [Java] 백준 7568 - 덩치
- [Java] 백준 1244 - 스위치 켜고 끄기
- [Node.js] 백준 19941 - 햄버거 분배
- [Node.js] 백준 1254 - 팰린드롬 만들기
- [Java] 백준 2589 - 보물섬
- [Java] 백준 2309 - 일곱 난쟁이
- [Java] 백준 1789 - 수들의 합
- [Java] 백준 1987 - 알파벳
- [Node.js] [Rust] 백준 24460 - 특별상이라도 받고 싶어
- [Node.js] 백준 7576 - 탑 보기
- [Rust] 백준 1047 - 울타리 (N^4 브루트포스 + 그리디)
- [Node.js] 백준 9657 - 돌게임3
- [Rust] 백준 4963 - 섬의 개수
- [Node.js] 프로그래머스 - 모의고사 / 실패율
- [Rust] 백준 2667 - 단지번호붙이기
- [Node.js] 프로그래머스 - 방문 길이
- [Node.js] 프로그래머스 - 괄호 회전하기
- [Rust] 백준 1002 - 터렛
- [Node.js] 프로그래머스 - 크레인 인형뽑기 게임
- [Node.js] 프로그래머스 - 기능개발
- [Rust] 백준 13717 - 포켓몬 GO
- [JavaScript] 백준 1092 - 배
- [Rust] 백준 25329 - 학생별 통화 요금 계산
백준 1987 - 알파벳
접근
- 이미 방문한 알파벳을 기억하자.
- 경로가 막히면 되돌아가자.
추가적으로 R과 C의 크기는 최대 20.
재귀로 풀어도 문제가 없겠다!
코드 구현
- 전역 변수 및 초기화
static int R, C;
static char[][] letterArr;
static int[] dr = { -1, 1, 0, 0 }; // 상, 하, 좌, 우 이동
static int[] dc = { 0, 0, -1, 1 };
static int ans; // 정답(최대 이동 칸 수)을 저장할 변수
- main 함수
public static void main(String[] args) throws IOException {
// DFS 시작 전, 시작점 (0,0)의 알파벳을 Set에 추가
Set<Character> passed = new HashSet<>();
passed.add(letterArr[0][0]);
// DFS 호출
dfs(0, 0, 1, passed);
System.out.println(ans);
}
depth의 경우 시작 칸을 포함하므로 1 부터 시작한다.
- dfs 함수
public static void dfs(int r, int c, int depth, Set<Character> visited) {
ans = Math.max(ans, depth); // 현재까지 이동한 칸 수로 ans 갱신
for (int i = 0; i < 4; i++) {
int newR = r + dr[i];
int newC = c + dc[i];
// 1. 다음 위치가 보드 범위 내에 있는지 확인
// 2. 다음 위치의 알파벳이 이전에 방문한 적 없는지 확인
if (newR >= 0 && newR < R && newC >= 0 && newC < C && !visited.contains(letterArr[newR][newC])) {
// 백트래킹 과정
visited.add(letterArr[newR][newC]); // 다음 알파벳을 방문했다고 표시
dfs(newR, newC, depth + 1, visited); // 재귀 호출
visited.remove(letterArr[newR][newC]); // 재귀가 끝나면 방문 표시 해제 (백트래킹)
}
}
}
HashSet 자체가 빨라서 문제는 없었음.
백트래킹 -> visited.remove(알파벳)을 통해,
한 경로를 깊게 탐색 후 돌아와 다른 경로를 탐색하는 “되돌리기”
정답
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
public class Main {
static int R, C;
static char[][] letterArr;
static int[] dr = { -1, 1, 0, 0 };
static int[] dc = { 0, 0, -1, 1 };
static int ans;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stringTk = new StringTokenizer(br.readLine());
R = Integer.parseInt(stringTk.nextToken());
C = Integer.parseInt(stringTk.nextToken());
letterArr = new char[R][C];
for (int r = 0; r < R; r++) {
String line = br.readLine();
for (int c = 0; c < C; c++) {
letterArr[r][c] = line.charAt(c);
}
}
Set<Character> passed = new HashSet<>();
passed.add(letterArr[0][0]);
dfs(0, 0, 1, passed);
System.out.println(ans);
}
public static void dfs(int r, int c, int depth, Set<Character> visited) {
ans = Math.max(ans, depth);
for (int i = 0; i < 4; i++) {
int newR = r + dr[i];
int newC = c + dc[i];
if (newR >= 0 && newR < R && newC >= 0 && newC < C && !visited.contains(letterArr[newR][newC])) {
visited.add(letterArr[newR][newC]);
dfs(newR, newC, depth + 1, visited);
visited.remove(letterArr[newR][newC]);
}
}
}
}
여전히 어렵다 자바!