꾸물꾸물 졔의 개발공부

[백준] 1520 내리막 길 - JAVA 본문

알고리즘/백준

[백준] 1520 내리막 길 - JAVA

체제 2023. 8. 15. 11:47

https://www.acmicpc.net/problem/1520

 

1520번: 내리막 길

여행을 떠난 세준이는 지도를 하나 구하였다. 이 지도는 아래 그림과 같이 직사각형 모양이며 여러 칸으로 나뉘어져 있다. 한 칸은 한 지점을 나타내는데 각 칸에는 그 지점의 높이가 쓰여 있으

www.acmicpc.net

 

 

[알고리즘]

  • DFS + DP 
  • 출발지에서 도착지까지의 경로를 찾기위해 그래프 탐색 방법 중 DFS 구현 (최단거리 구하기 x) 
  • 🌟고려해야 할 부분 
    1. 그래프의 최대 크기 : 500 x 500
    2. 모든 지점에서 4방향으로 이동이 가능할 경우, 스택에 엄청난 재귀함수가 쌓이면서 메모리초과가 발생 할 수 있다. 
    3. DP를 사용하여 이미 탐색한 경로에 대해서는 중복 연산을 제거한다. 
  • dp[x][y] = 해당 지점에서 목표지점까지 갈 수 있는 경로의 수  

 

[설계]

  • dp 값을 0이 아닌 -1 로 초기화한다. 
    1. 이미 탐색했던 경로에 대해서는 중복 탐색하지 않기 위해 dp 사용 
    2. 즉, 각 위치에 대해 (아직 탐색하지 않은 위치 = -1 ) / (이미 탐색했지만 경로가 없음) 을 구분해야 한다.
  • dp 값에 따른 표시 
    1. dp[x][y] = -1 : 아직 탐색하지 않은 지점
    2. dp[x][y] = 0 : 탐색했지만, 목적지에 도달할 수 없는 지점 (가능한 경로 0개) 
    3. dp[x][y] = n(>0) : 탐색하였고, 목적지에 도달할 수 있는 경로가 n개 
  • DFS 탐색의 재귀호출을 통해, 4방향 중 내리막길로 이동하면서 목적지에 도착했을 경우 1, 이미 탐색한 경로를 만났을 경우 해당 dp값을 반환하여 현재 경로에 더해준다.

 

[구현 과정]

  • map[][] : 입력값으로 주어지는 지도 정보 저장 배열 
  • dp[x][y] : (x,y) 위치에서 목적지인 (N-1, M-1) 까지의 가능한 경로의 수 

 

1. 입력값으로 주어지는 지도 값을 int형 2차원 배열인 map에 저장한다. 

 

2. dp배열을 map 과 같은 크기로 생성 후, -1로 초기화한다. (-1 == 아직 탐색하지 않은 지점) 

 

3. (0,0)인 시작점에서 부터 DFS 탐색을 시작한다. 

 

4. DFS 구현 과정은 다음과 같다.

  • 현재 탐색하고 있는 지점(x,y) 의 dp 값을 0으로 바꾼다. (탐색한 지점이라는 표시)
  • 4방향으로 탐색하며 지도의 범위를 벗어날 경우 continue 
  • 이동할 수 있는 내리막길일 경우, 현재위치의 dp값에 다음 위치(nx,ny)의 dfs 결과값을 더한다. (재귀호출하다가 이후에 return 되는 값이 더해짐)
  • 목적지에 도착했다면 1을 반환한다. 
  • 만약 dp값이 -1이 아닌 지점을 만났다면 이미 탐색한 경로이므로 중복 탐색할 필요가 없다. 저장되어있는 dp값 반환.
    👉 저장되어있는 dp값 : 해당 위치로부터 목적지까지의 가능한 경로 수  
  • 반환된 값은 재귀를 벗어나며 이동해 온 모든 지점의 dp값에 더해진다. 

 

 

5. 최종적으로 dp[0][0] 출력. (=시작점에서 목적지까지의 가능한 경로의 수) 

 


 

[소스 코드]

import java.util.*;
import java.io.*;

public class Main {
	static int N,M;
	static int[][] map; 
	static int[][] dp; 
	
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
		StringTokenizer st= new StringTokenizer(br.readLine(), " ");
		
		N= Integer.parseInt(st.nextToken());
		M= Integer.parseInt(st.nextToken()); 
		
		map = new int[N][M];
		dp = new int[N][M]; //해당 지점에서 목적지까지 갈수 있는 경로의 갯수 
		
		for(int i=0; i<N; i++) {
			st= new StringTokenizer(br.readLine(), " "); 
			for(int j=0; j<M; j++) {
				map[i][j]= Integer.parseInt(st.nextToken());
			}
		}
		
		for(int i=0; i<N; i++) {
			Arrays.fill(dp[i], -1);
		} 
        
		int res= dfs(0,0); 
		System.out.println(res);

	}//end of main
	
	static int dx[]= {-1,0,1,0};
	static int dy[]= {0,-1,0,1}; //상 좌 하 우 
	
	//0,0에서 시작하여 깊이우선 탐색 
	private static int dfs(int x, int y) {
		if(x==N-1 && y==M-1) return 1; //목적지까지의 경로 1추가
		
		if(dp[x][y] != -1) return dp[x][y]; //이미 한번 탐색한 경로 등장 
		
		dp[x][y] =0; //해당 위치에서 탐색 
		for(int d=0; d<4; d++) {
			int nx = x+dx[d];
			int ny = y+dy[d]; 
			
			if(isOut(nx, ny)) continue;
			
			//이동 가능 
			if(map[nx][ny] < map[x][y]) {
				dp[x][y] += dfs(nx,ny); 
			}
		}
        
		return dp[x][y];
	}
	
	private static boolean isOut(int x, int y) {
		return x<0 || x>=N || y<0 || y>=M; 
	}
}//end of class

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 5972 택배 배송 - JAVA  (0) 2023.08.17
[백준] 2096 내려가기 - JAVA  (0) 2023.08.16
[백준] 9935 문자열 폭발 - JAVA  (0) 2023.08.14
[백준] 13023 ABCDE - JAVA  (0) 2023.08.11
[백준] 2589 보물섬 - JAVA  (0) 2023.08.10