• Home
  • About
    • Yerim Oh photo

      Yerim Oh

      Happy and worthwhile day by day :)

    • Learn More
    • Email
    • LinkedIn
    • Instagram
    • Github
    • Youtube
  • Posts
    • All Posts
    • All Tags
  • Projects

[1016] (파이썬) CODE TREE_Lv.2 Intermediate Low: 정수 사각형 최대 합

14 Jan 2020

Reading time ~4 minutes

Table of Contents
  • 문제
    • 입력 형식
    • 출력 형식
    • 입출력 예제
    • 예제 설명
  • Backtracking
    • 풀이과정
    • 코드
    • 결과
  • DP (Tabulation)
    • 0) 입력값 받기
    • 1) 격자 내 탐색
    • 1.5) 끝 행 처리
    • 최대 합 구하기
    • 코드
    • 결과

문제

[정수 사각형 최대 합]
풀러 가기

N* N 행렬이 주어졌을 때, (1, 1)에서 시작하여 오른쪽 혹은 밑으로만 이동하여 (N, N)으로 간다고 했을 때 거쳐간 위치에 적혀있는 숫자의 합을 최대로 하는 프로그램을 작성해보세요.

입력 형식

첫째 줄에는 N이 주어집니다.

두 번째 줄 부터 N개의 줄에 각각 각 행에 해당하는 N개의 정수 값이 공백을 사이에 두고 주어집니다.

  • 1 ≤ N ≤ 100

  • 1 ≤ 행렬에 주어지는 숫자 ≤ 1,000,000

출력 형식

가능한 최대 합을 출력합니다.

Constraints:
시간 제한: 1000ms
메모리 제한: 80MB

입출력 예제

입력:
3
1 2 3
3 2 1
4 2 1

출력: 
11
입력:
3
1 3 2
3 4 5
4 2 1

출력: 
14

예제 설명

첫 번째 예제의 경우 다음과 같이 이동하면 합이 11이 되며, 더 좋은 답은 존재하지 않습니다 image


풀이

Backtracking

backtracking과정에서 전역변수에 갱신해주는 방식의 함수 사용
탐색 가능한 모든 위치를 방문하며 도착점에 도달했을 떄 최대 합의 값을 갱신
🚫 시간이 오래걸려서 통과가 안 될 것이다

풀이과정

시작점 (0.0)부터 시작하여 방문 가능한 모든 위치를 탐색(도착점은 (N-1,N-1))
탐색방향인 아래, 오른쪽 방향에 대해 격자 내에 위치하면 각 위치로 이동하여 탐색
아래방향과 오른쪽 방향만 이동이 가능하므로 dx dy 테크닉을 이용하여 주어진 방향으로만 탐색

  • 아래 방향: D
  • 오른쪽 방향: R

코드

n = int(input())

grid = [
    list(map(int, input().split()))
    for _ in range(n)
]

max_sum = 0

def in_range(x, y):
    return 0 <= x and x < n and 0 <= y and y < n


def find_max_sum(x, y, sum):
    global max_sum
    
    # 도착 지점에 도착하면 최대 합을 갱신해줍니다.
    if x == n - 1 and y == n - 1:
        max_sum = max(max_sum, sum)
        return
    
    dxs, dys = [1, 0], [0, 1]
    
    # 가능한 모든 방향에 대해 탐색해줍니다.
    for dx, dy in zip(dxs, dys):
        new_x, new_y = x + dx, y + dy
        
        if in_range(new_x, new_y):
            find_max_sum(new_x, new_y, sum + grid[new_x][new_y])
                         
                    
find_max_sum(0, 0, grid[0][0])
print(max_sum)

결과

image 흑… 역시 안된다!!


DP (Tabulation)

동일한 상태를 정의하기 위한 요소

  • 시작점에서 출발하려 마지막으로 방문한 위치
  • 선택된 경로의 숫자 합

➡ 문제에서 최대 합을 구하라고 하였으므로 ‘시작점에서 출발하여 마지막으로 방문한 위치’ 가 동일한 경우,
‘선택된 경로의 숫자 합’ 이 최대가 되어야 한다

0) 입력값 받기

image

👀 코드 보기
# 입력값
n = int(input())

num = [
    list(map(int, input().split()))
    for _ in range(n)
]

# 기록할 것
dp = [
    [0 for _ in range(n)]
    for _ in range(n)
]

1) 격자 내 탐색

시작점에서 출발하여 마지막으로 방문한 위치가 동일한 상황에서,
1️⃣ 해당 위치까지 이동한 경로에 적힌 숫자들의 합의 경로의 전단계에서 방문한 노드(아래로 이동하기 전, 오른쪽으로 이동하기 전) 확인

  • 바로 전 노드에서 아래 방향으로 이동하여 (i,j)로 오게 된 경우
    • 이 경우 전 노드까지의 합인 dp[i-1][j] 에 이동 후의 수인 num[i][j]를 더해주면 된다.
  • 바로 전 노드에서 오른쪽 방향으로 이동하여 (i,j)로 오게 된 경우
    • 이 경우 전 노드까지의 합인 dp[i][j-1] 에 이동 후의 수인 num[i][j]를 더해주면 된다.

2️⃣ 이 노드 중에서 더 큰 값을 선택
dp[i][j] = max(dp[i-1][j] , dp[i][j-1]) + num[i][j]

image

1.5) 끝 행 처리

[최좌측 열 처리]
전 행이 오른쪽 방향 에서 내려온 게 없음
전 행이 아래 방향 에서 왔다는 것만 생각해주면 된다
dp[i][0] = dp[i-1][0] + num[i][0] 로 값을 채워주면 된다
image

👀 코드 보기
    # 최좌측 열의 초기값을 설정해줍니다.
    for i in range(1, n):
        dp[i][0] = dp[i-1][0] + num[i][0]

[최상단 행 처리]
전 행이 아래 방향 에서 내려온 게 없음
전 행이 오른쪽 방향 에서 왔다는 것만 생각해주면 된다
dp[0][j] = dp[0][j-1] + num[0][j] 로 값을 채워주면 된다
image

👀 코드 보기
    # 최상단 행의 초기값을 설정해줍니다.
    for j in range(1, n):
        dp[0][j] = dp[0][j-1] + num[0][j]

프레젠테이션1

최대 합 구하기

격자 내 모든원소에 대한 탐색이 끝난 후,
dp[N-1][N-1] 값: (0,0) 에서 시작해 (N-1,N-1)까지 도달할 떄의 최대합이 들어있게 됨 ➡ 해당 값을 출력해주면 된다

👀 코드 보기
# 탐색하는 위치의 위에 값과 좌측 값 중에 큰 값에
# 해당 위치의 숫자를 더해줍니다. 
for i in range(1, n):
    for j in range(1, n):
        dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + num[i][j]
        
print(dp[n-1][n-1])

전 노드가 더 큰 곳에서 화살표를 보냈다
프레젠테이션1

코드

n = int(input())

num = [
    list(map(int, input().split()))
    for _ in range(n)
]

dp = [
    [0 for _ in range(n)]
    for _ in range(n)
]

def initialize():
    # 시작점의 경우 dp[0][0] = num[0][0]으로 초기값을 설정해줍니다
    dp[0][0] = num[0][0]
    
    # 최좌측 열의 초기값을 설정해줍니다.
    for i in range(1, n):
        dp[i][0] = dp[i-1][0] + num[i][0]
    
    # 최상단 행의 초기값을 설정해줍니다.
    for j in range(1, n):
        dp[0][j] = dp[0][j-1] + num[0][j]
        
        
# 초기값 설정
initialize()

# 탐색하는 위치의 위에 값과 좌측 값 중에 큰 값에
# 해당 위치의 숫자를 더해줍니다. 
for i in range(1, n):
    for j in range(1, n):
        dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + num[i][j]
        
print(dp[n-1][n-1])

결과

image 쨔쨘



Coding test Share Tweet +1