본문으로 바로가기

[DP] 11048번 이동하기

category Algorithm/BOJ 문제풀이 2019. 2. 6. 15:21
11048_이동하기

11048번 이동하기

 

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


 

문제

준규는 N×M 크기의 미로에 갇혀있다. 미로는 1×1크기의 방으로 나누어져 있고, 각 방에는 사탕이 놓여져 있다. 미로의 가장 왼쪽 윗 방은 (1, 1)이고, 가장 오른쪽 아랫 방은 (N, M)이다.

준규는 현재 (1, 1)에 있고, (N, M)으로 이동하려고 한다. 준규가 (r, c)에 있으면, (r+1, c), (r, c+1), (r+1, c+1)로 이동할 수 있고, 각 방을 방문할 때마다 방에 놓여져있는 사탕을 모두 가져갈 수 있다. 또, 미로 밖으로 나갈 수는 없다.

준규가 (N, M)으로 이동할 때, 가져올 수 있는 사탕 개수의 최댓값을 구하시오.

 

입력

첫째 줄에 미로의 크기 N, M이 주어진다. (1 ≤ N, M ≤ 1,000)

둘째 줄부터 N개 줄에는 총 M개의 숫자가 주어지며, r번째 줄의 c번째 수는 (r, c)에 놓여져 있는 사탕의 개수이다. 사탕의 개수는 0보다 크거나 같고, 100보다 작거나 같다.

 

출력

첫째 줄에 준규가 (N, M)으로 이동할 때, 가져올 수 있는 사탕 개수를 출력한다.

 

예제 입력

3 4
1 2 3 4
0 0 0 5
9 8 7 6
3 3
1 0 0
0 1 0
0 0 1
4 3
1 2 3
6 5 4
7 8 9
12 11 10

 

예제 출력

31
3
47

 

해결방법

Shortest Path 유형의 DP 문제이다

 

 

⭐️ 솔루션 ⭐️

먼저 시작점 (1,1) 에서 (n,m) 까지 반복문을 돌며 최대값을 저장한다

이 때, (i,j) 의 사탕 최대값은 (i-1, j) (i, j-1) (i-1, j-1) 중의 최대값 + a[i][j] 이다

 

 

1️⃣ Bottom-up 방식

  • 2중 for문으로 한 행씩 d 배열에 최대값을 저장한다
  • Index는 1,1 부터 시작하는데 0행과 0열은 전부 0이기 때문에 따로 초기값을 설정해주지 않아도 된다

 

2️⃣ Top-down 방식

  • 재귀를 사용해서 구현한다
  • row, col 이 둘 다 1이라면 return 1을 해준다
  • 만약 범위를 벗어나면 (row와 col이 1보다 작다면) return 0을 해준다
  • memoization을 위해 d 배열을 -1로 초기화한다 (만약 d가 0보다 크다면 return d[row][col])

 

 

 

소스코드

1️⃣ Bottom-up

#include <iostream>
#include <cstring>
#include <math.h>
#include <algorithm>
#define MAX 1001
using namespace std;

int n,m;
int map[MAX][MAX];
int d[MAX][MAX];

void dp(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            d[i][j] = max(d[i-1][j-1],max(d[i-1][j],d[i][j-1])) + map[i][j];
        }
    }
    
    cout << d[n][m] << "\n";
}

int main(int argc, const char * argv[]) {
    // cin,cout 속도향상
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    cin >> n >> m;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            cin >> map[i][j];
        }
    }
    
    dp();
    
    return 0;
}

 

2️⃣ Top-down

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define MAX 1001
#define INF 987654321
using namespace std;

int n,m;
int a[MAX][MAX];
int d[MAX][MAX];

int top_down(int row,int col){
    // 답을 찾았다면
    if(row==1 && col==1) return a[1][1];
    // 범위를 벗어난다면
    if(row<1 || col<1) return 0;
    // Memo가 되어있다면
    if(d[row][col] >= 0) return d[row][col];

    d[row][col] = max(max(top_down(row-1, col),top_down(row, col-1)),top_down(row-1, col-1)) + a[row][col];

    return d[row][col];
}

int main(int argc, const char * argv[]) {
    // cin,cout 속도향상
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    cin >> n >> m;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            cin >> a[i][j];
        }
    }
    
    memset(d, -1, sizeof(d));
    cout << top_down(n, m) << endl;
}

 

 

'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[DP] 12865번 평범한 배낭  (2) 2019.02.06
[DP] 1890번 점프  (0) 2019.02.06
[DP] 2579번 계단 오르기  (0) 2019.02.06
[DP] 1912번 연속합  (0) 2019.02.06
[DP] 2133번 타일 채우기  (0) 2019.02.06