목차
문제 : boj2418
필요 알고리즘
- DP (동적 계획법)
- BFS 같은걸론 시간초과가 나게된다. 동적 계획법으로 풀 수 있는 문제이다.
※ 제 코드에서 왜 main 함수에 로직을 직접 작성하지 않았는지, 왜 Scanner를 쓰지 않고 BufferedReader를 사용했는지 등에 대해서는 '자바로 백준 풀 때의 팁 및 주의점' 글을 참고해주세요. 백준을 자바로 풀어보려고 시작하시는 분이나, 백준에서 자바로 풀 때의 팁을 원하시는 분들도 보시는걸 추천드립니다.
풀이
'각 칸은 중복되게 사용해도 된다.' 부분이 문제인데, 이 부분때문에 BFS나 DFS로 진행 시 중복체크를 못하므로 시간복잡도가 저 멀리 가버리게 된다. 게다가 경우의 수의 경우 최대 10^18 이라고 했으므로, 따로 시간복잡도를 계산해보지 않아도 10^18번 찾는건 불가함을 알 수 있다.
DP로 접근하면 생각보다 쉽게 풀 수 있다.
dp[a][b][c]를 (a, b) 칸에서 입력된 문자 중 c번 인덱스 문자까지 읽는 경우의 수라고 정의해보자.
이 경우 dp[a][b][c]는 c번 인덱스 문자가 'X'이고, c-1번 인덱스 문자가 'Y'라고 하면 (a,b)칸에 'X'가 존재할 경우 그 주변 8칸에 'Y'가 존재할 경우 그 경우의수를 더해주면 된다. 예를들어 (a-1, b-1)이 'Y'였다면 dp[a][b][c] += dp[a-1][b-1][c-1]이 된다.
예제 입력 1의 경우를 보자.
3 4 5
ERAT
ATSR
AUTU
TARTU
dp[a][b][0] 부터 dp[a][b][5]를 dp[a][b] 까지만 나타내보면 다음과 같다. 각 칸의 문자는 입력으로 줄어졌던 격자의 문자이고, 숫자는 dp 배열에 담긴 경우의 수를 나타낸다. 다만 회색 숫자는 바로 직전(c-1)의 숫자를 알아보기 편하게 적어둔 것이다.
코드 : github
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in), 1 << 16);
public static void main(String[] args) throws Exception {
new Main().solution();
}
public void solution() throws Exception {
StringTokenizer st = new StringTokenizer(br.readLine());
int r = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
int len = Integer.parseInt(st.nextToken());
char[][] arr = new char[r][c];
for (int i = 0; i < r; i++) {
String cur = br.readLine();
for (int j = 0; j < c; j++) {
arr[i][j] = cur.charAt(j);
}
}
String word = br.readLine();
long[][][] dp = new long[r][c][len];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (arr[i][j] == word.charAt(0))
dp[i][j][0] = 1;
}
}
long answer = 0;
for (int k = 1; k < len; k++) {
char cur = word.charAt(k);
char bf = word.charAt(k-1);
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (arr[i][j] != cur) continue;
for (int dr = -1; dr <= 1; dr++) {
for (int dc = -1; dc <= 1; dc++) {
if (dr==0 && dc==0) continue;
int nr = i+dr;
int nc = j+dc;
if (nr<0||nr>=r||nc<0||nc>=c||arr[nr][nc]!=bf) continue;
dp[i][j][k] += dp[nr][nc][k-1];
}
}
if (k == len-1) answer += dp[i][j][k];
}
}
}
System.out.println(answer);
}
}
'PS > BOJ' 카테고리의 다른 글
[자바] 백준 30025 - K의 배수 (java) (0) | 2023.12.12 |
---|---|
[자바] 백준 1477 - 휴게소 세우기 (java) (0) | 2023.12.08 |
[자바] 백준 30646 -최대 합 순서쌍의 개수(java) (0) | 2023.12.06 |
[자바] 백준 20500 - Ezreal 여눈부터 가네 ㅈㅈ(java) (0) | 2023.12.05 |
[자바] 백준 1612 - 가지고 노는 1 (java) (0) | 2023.12.04 |
댓글