have a good time 2024. 8. 27. 22:18

 

 

 

dp 와 dfs 를 이용한다.

 

거꾸로 찾아나가는 방식이다.

BREAK 이 문자를 찾아나가야 할 때,

 

dp[1][2][3] = 위치(1,2) 에서 시작된 문자로 

BREAK 문자열의 3번째 부터 끝 문자열까지 완성할 수 있는 경우의 수이다.

즉, AK 를 완성할 수 있는 경우의 수로,

 

KAKT
XEAS
YRWU
ZBQP

 

위치 (1,2) 의 문자열 = A인데,

여기에서 좌,우,위, 아래로 움직여서 K가 있는 경우를 찾아보면 한 가지 경우를 찾을 수 있다.

때문에 dp[1][2][3] = 1 이다.

 

 

 

(1) 코드 설명 

 

KAKT
XEAS
YRWU
ZBQP

 

1) 

BREAK에서 맨 처음 문자 B가 있는 위치(3,1)에서 dfs가 시작한다.

 

 

===============================

 

KAKT
XEAS
YRWU
ZBQP

 

2) 

(3,1)의 위치에서 좌,우,위,아래 방향으로 다음 글자인

R이 있는 위치 (2,1) 에서 또 dfs가 진행된다.

 

 

====================================

 

 

 

 

KAKT
XEAS
YRWU
ZBQP

 

 

3) 

(2,1)의 위치에서 좌,우,위,아래 방향으로 다음 글자인

E가 있는 위치 (1,1) 에서 또 dfs가 진행된다.

 

 

=======================================

 

 

4) 

KAKT
XEAS
YRWU
ZBQP

 

(1,1)의 위치에서 좌,우,위,아래 방향으로 다음 글자인

A가 있는 위치 (0,1) 에서 또 dfs가 진행된다.

 

============================================

 

5) 

KAKT
XEAS
YRWU
ZBQP

 

(0,1)의 위치에서 좌,우,위,아래 방향으로 다음 글자인

K가 있는 위치 (0,2) 에서 또 dfs가 진행된다.

 

 

==========================================

 

그런데 이제 마지막 글자이므로 

이 경우는 값 1을 리턴한다.

그래서 dp[0][2][4] = 1 이다. 

즉 위치 (0,2) 에서 A를 만들 수 있는 경우의 수가 1이다.

 

그러면 dp[0][1][3] 에는 1이 더해지게 된다. 

즉, 위치 (0,1) 에서 AK를 만들 수 있는 경우가 1만큼 증가함.

 

 

 

이런 식으로 아래에서부터 위로 올라가는 형식으로 해결하면 된다. 

 

 

 

 

맨 처음 dp 배열을 모두 -1 로 채운 이유는 방문하지 않았음을 표현하는 것이다.

 

 

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


public class Main {
	
	static char[][] board;
	static int dp[][][];
	static int N;
	static int M;
	static int K;
	static String word;
	
    public static void main(String[] args)  throws IOException {  
    	
    	  BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          StringTokenizer st = new StringTokenizer(br.readLine(), " ");
          N = Integer.parseInt(st.nextToken());
          M = Integer.parseInt(st.nextToken());
          K = Integer.parseInt(st.nextToken());
          board = new char[N][M];
	
		  for (int i = 0; i < N; i++) {
		          String input = br.readLine();
		         
		          for (int j = 0; j < M; j++) {
		              board[i][j] = input.charAt(j);
		          }
		      }	  
		  
		  	word = br.readLine();
			
			   dp = new int[N][M][word.length()];
			   for (int i = 0; i < N; i++) {
		              for (int j = 0; j < M; j++) {
		                  Arrays.fill(dp[i][j], -1);
		              }
		          }
			  long count = 0;
			  for(int i=0; i<N; i++) {
				  for(int j =0; j<M; j++) {
					  
					  if(board[i][j] == word.charAt(0)){
					
						  count+=dfs(i,j,0);						  
					  }						  
			  }
    }
    
  System.out.println(count);
     
}
    

    public static int dfs(int x, int y, int length) {
	
    	
    	if(dp[x][y][length]!=-1) {    	
    		return dp[x][y][length];
    		
    	}
   
    	if(length == (word.length()-1)) {    	
    		return dp[x][y][length]=1;
    		
    	}
    	
    	dp[x][y][length] = 0;
    	
    	int dx[] = {-1,1,0,0};
    	int dy[] = {0,0,-1,1};
	
    	for(int i=1; i<=K; i++) {
	    	for(int j=0; j<4; j++) {
	    		
	    		int nextX = x + dx[j]*i;
	    		int nextY = y + dy[j]*i;	    		
	    		
	    		if(nextX>=0 && nextX<N && nextY>=0 && nextY<M) {
	    		
	    			if (board[nextX][nextY] == word.charAt(length+1)){
	    				
	    				dp[x][y][length] += dfs(nextX, nextY,length+1);    				
	    			}    			
	    		}
	    	}
    }
    	
    	
    	return dp[x][y][length];
  }
}

 

 

참고 블로그 : [알고리즘/백준] 2186번: 문자판 (JAVA) (velog.io)

 

[알고리즘/백준] 2186번: 문자판 (JAVA)

백준 2186번: 문자판 문제 입출력 문제 접근법 문제를 읽어보고 미로 찾기와 비슷한 유형의 문제라고 생각하며 풀이를 진행했다. 처음 문제를 풀며 신경 쓴 부분은 다음과 같다. 방향 배열 dx, dy를

velog.io