티스토리 뷰

728x90
반응형

목차

     

    문제

     

    여행을 떠난 세준이는 지도를 하나 구하였다. 

    이 지도는 아래 그림과 같이 직사각형 모양이며 여러 칸으로 나뉘어 있다. 

    한 칸은 한 지점을 나타내는데 각 칸에는 그 지점의 높이가 쓰여 있으며, 

    각 지점 사이의 이동은 지도에서 상하좌우 이웃한 곳끼리만 가능하다.

     

    현재 제일 왼쪽 위 칸이 나타내는 지점에 있는 세준이는 제일 오른쪽 아래 칸이 나타내는 지점으로 가려고 한다. 

    그런데 가능한 힘을 적게 들이고 싶어 항상 높이가 더 낮은 지점으로만 이동하여 목표 지점까지 가고자 한다. 

    위와 같은 지도에서는 다음과 같은 세 가지 경로가 가능하다.

     

    지도가 주어질 때 이와 같이 제일 왼쪽 위 지점에서 출발하여 제일 오른쪽 아래 지점까지 

    항상 내리막길로만 이동하는 경로의 개수를 구하는 프로그램을 작성하시오.

     

    입력

     

    첫째 줄에는 지도의 세로의 크기 M과 가로의 크기 N이 빈칸을 사이에 두고 주어진다. 

    이어 다음 M개 줄에 걸쳐 한 줄에 N개씩 위에서부터 차례로 각 지점의 높이가 빈칸을 사이에 두고 주어진다. 

    M과 N은 각각 500이하의 자연수이고, 각 지점의 높이는 10000 이하의 자연수이다.

     

    출력

     

    첫째 줄에 이동 가능한 경로의 수 H를 출력한다. 모든 입력에 대하여 H는 10억 이하의 음이 아닌 정수이다.

     

    풀이

     

    문제가 뭔 소린진 알겠는데, DP로 어떻게 풀어야 하는지 감이 안 와서 손도 못 대고 있었다.

     

    그러다 다른 사람들의 풀이를 참고했는데, 무려 DFS를 함께 사용해야 하는 문제였다.

     

    DFS 하면 또 재귀함수니까.. 괜한 공포심도 들고 그랬다.

     

    어쨌거나 결론부터 말하자면, 이 문제는 DFS를 이용해 가능한 모든 경로를 탐색하며,

     

    그 와중에 DP를 이용해 중복 계산을 줄이며 답을 구하는 문제이다.

     

    알고리즘은 의외로 간단한데, 짧게 정리하면 아래와 같다.

     

    1. 입력값으로 m, n을 받은 뒤 m x n 이차원 배열 map과 dp를 만들고, map는 지도의 높이로, dp는 -1로 초기화한다.
      여기서 dp를 -1로 초기화하는 것은 방문하지 않은 칸을 나타내기 위함이라 꼭 -1이 아니어도 된다.
    2. dfs를 위한 함수를 정의한다. 해당 함수는 다음과 같이 동작한다.

      1. 도착점에 도달한 경우, 그러니까 x == m - 1 && y == n - 1인 경우 1을 리턴한다(종료 조건).
      2. 방문한 칸의 dp 값이 -1이 아니라면 이미 방문한 칸이므로 저장된 값을 반환해 중복 계산을 줄인다.
      3. -1이라면 4방향을 전부 탐색해 현재 칸보다 낮은 칸을 찾는다.
      4. 이동할 수 있는 칸을 찾았다면 dfs 함수를 재귀호출해서 해당 칸에 대해 탐색을 진행한다.
      5. 이렇게 이동한 칸에서의 경로의 수를 dp값에 더해준다.
        이렇게 하면 해당 위치에서 도착지점까지의 모든 가능한 경로가 저장된다.
      6. 이동이 끝나면 현재 칸의 dp값을 반환한다. 마찬가지로 이 값은 현재 칸에서 도착점까지 이동하는 경로의 수이다.
    3. dfs(0, 0)을 호출하고 결과를 출력한다.

     

    Java

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.StringTokenizer;
    
    public class Prob1520 {
    
    	static int m;
    	static int n;
    	static int[][] map;
    	static int[][] dp;
    	static int[] dx = {-1, 0, 1, 0};
    	static int[] dy = {0, 1, 0, -1};
    
    	public static void main(String[] args) throws IOException {
    
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    
    		m = Integer.parseInt(st.nextToken());
    		n = Integer.parseInt(st.nextToken());
    		map = new int[m][n];
    		dp = new int[m][n];
    
    		for (int i = 0; i < m; i++) {
    			st = new StringTokenizer(br.readLine());
    			for (int j = 0; j < n; j++) {
    				map[i][j] = Integer.parseInt(st.nextToken());
    				dp[i][j] = -1;
    			}
    		}
    		System.out.println(dfs(0, 0));
    	}
    
    	static int dfs(int x, int y) {
    		if (x == m - 1 && y == n - 1) {
    			return 1;
    		}
    		if (dp[x][y] != -1) {
    			return dp[x][y];
    		}
    		dp[x][y] = 0;
    		for (int i = 0; i < 4; i++) {
    			int nx = x + dx[i];
    			int ny = y + dy[i];
    			if (nx >= 0 && ny >= 0 && nx < m && ny < n) {
    				if (map[nx][ny] < map[x][y]) {
    					dp[x][y] += dfs(nx, ny);
    				}
    			}
    		}
    		return dp[x][y];
    	}
    }

     

    Python

     

    import sys
    
    m, n = map(int, sys.stdin.readline().rstrip().split(" "))
    map = [list(map(int, sys.stdin.readline().rstrip().split(" "))) for _ in range(m)]
    dp = [[-1 for _ in range(n)] for _ in range(m)]
    dx = [-1, 0, 1, 0]
    dy = [0, 1, 0, -1]
    
    
    def dfs(x, y):
        if x == m - 1 and y == n - 1:
            return 1
        if dp[x][y] != -1:
            return dp[x][y]
        dp[x][y] = 0
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx >= 0 and ny >= 0 and nx < m and ny < n:
                if map[nx][ny] < map[x][y]:
                    dp[x][y] += dfs(nx, ny)
        return dp[x][y]
    
    
    print(dfs(0, 0))

     

    Performance

     

    반응형
    댓글
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    «   2024/06   »
    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
    글 보관함