Lv3. 등굣길 ( Python )


Lv3. 등굣길

# 문제 설명

계속되는 폭우로 일부 지역이 물에 잠겼습니다. 물에 잠기지 않은 지역을 통해 학교를 가려고 합니다. 집에서 학교까지 가는 길은 m x n 크기의 격자모양으로 나타낼 수 있습니다.

아래 그림은 m = 4, n = 3 인 경우입니다.

image0.png

가장 왼쪽 위, 즉 집이 있는 곳의 좌표는 (1, 1)로 나타내고 가장 오른쪽 아래, 즉 학교가 있는 곳의 좌표는 (m, n)으로 나타냅니다.

격자의 크기 m, n과 물이 잠긴 지역의 좌표를 담은 2차원 배열 puddles이 매개변수로 주어집니다. 집에서 학교까지 갈 수 있는 최단경로의 개수를 1,000,000,007로 나눈 나머지를 return 하도록 solution 함수를 작성해주세요.

# 제한 사항
  • 격자의 크기 m, n은 1 이상 100 이하인 자연수입니다.
    • m과 n이 모두 1인 경우는 입력으로 주어지지 않습니다.
  • 물에 잠긴 지역은 0개 이상 10개 이하입니다.
  • 집과 학교가 물에 잠긴 경우는 입력으로 주어지지 않습니다.

# 입출력 예

m n puddles return
4 3 [[2, 2]] 4
입출력 예 설명

image1.png


문제 해결 시 고려사항

  • 최단 경로의 수를 구하기 위하 점화식의 작성

본 문제는 주어지는 크기의 격자모양 내에서 (1,1) 위치의 집으로부터 (m,n) 위치의 학교까지 갈 수 있는 최단 거리의 경우의 수를 구하는 문제이다. 하지만 격자 내에는 물 웅덩이가 존재하며 물 웅덩이의 위치로의 이동은 이루어 질 수 없다. 따라서 필자는 DP를 활용하여 물 웅덩이의 위치를 고려한 점화식 작성으로 문제를 해결하였다. 그 과정은 아래와 같다.

  1. dp 값(경로의 수)를 담을 리스트와 문제에서 주어지는 격자 모양의 지도를 나타내기 위한 board 리스트를 생성

     # dp, board 리스트 생성(0의 값 할당)
     dp = [[0]*(m+1) for _ in range(n+1)]
     board = [[0]*(m+1) for _ in range(n+1)]
    
  2. 물 웅덩이(puddles)의 위치를 구분 짓기 위해 board에 -1의 값을 할당

      # 웅덩이에 해당하는 위치를 구분짓기 위해 -1로 값 할당
       for i in range(len(puddles)):
         board[(puddles[i][1])][(puddles[i][0])] = -1
    
  3. 웅덩이를 피해 등교할 수 있는 경로의 수를 구하기 위한 탐색 실시

    1. 현재 위치가 시작 지점(집)이라면 1로 초기화

       # 현재 위치가 시작 지점이라면 dp값을 1로 초기화
       if i == 1 and j == 1:
         dp[i][j] = 1
      
    2. 현재 위치가 웅덩이라면 dp 값에 대한 처리 없이 통과 => dp는 0의 값을 가져 이동할 수 없다는 의미

       # 현재 위치가 웅덩이라면 dp 값에 변화를 주지 않고 통과(dp 값은 0)
       # 0은 해당 위치로 이동할 수 있는 경로가 없다는 의미를 가짐
       elif board[i][j] == -1:
         continue
      
    3. 현재 위치가 시작 지점과 웅덩이가 아니라면 현재 위치기 기준 좌측과 상단의 dp 값을 더하여 현재 위치까지의 경로의 수를 계산 => 최단 거리로 이동하기 위해서는 우측과 하단으로의 이동만 이루어져야 하기 때문

       else: 
         # 최단 거리로 움직이려면 우측과 하단으로의 이동만 이루어지기 때문에
         # 현재 위치의 상단과 좌측의 dp 값을 더하여 경로의 수를 계산
         dp[i][j] += (dp[i-1][j] % 1000000007 + dp[i][j-1] % 1000000007) % 1000000007
      


전체 코드

def solution(m, n, puddles):
    # dp, board 리스트 생성(0의 값 할당)
    dp = [[0]*(m+1) for _ in range(n+1)]
    board = [[0]*(m+1) for _ in range(n+1)]
    # 웅덩이에 해당하는 위치를 구분짓기 위해 -1로 값 할당
    for i in range(len(puddles)):
        board[(puddles[i][1])][(puddles[i][0])] = -1
    # 웅덩이를 피해 등교할 수 있는 최단 루트 경우의 수 탐색
    for i in range(1, n+1):
        for j in range(1, m+1):
            # 현재 위치가 시작 지점이라면 dp값을 1로 초기화
            if i == 1 and j == 1:
                dp[i][j] = 1
            # 현재 위치가 웅덩이라면 dp 값에 변화를 주지 않고 통과(dp 값은 0)
            # 0은 해당 위치로 이동할 수 있는 경로가 없다는 의미를 가짐
            elif board[i][j] == -1:
                continue
            # 현재 위치가 웅덩이가 아니라면 
            else: 
                # 최단 거리로 움직이려면 우측과 하단으로의 이동만 이루어지기 때문에
                # 현재 위치의 상단과 좌측의 dp 값을 더하여 경로의 수를 계산
                dp[i][j] += (dp[i-1][j] % 1000000007 + dp[i][j-1] % 1000000007) % 1000000007
    return dp[n][m]% 1000000007