[백준] 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)으로 이동할 때, 가져올 수 있는 사탕 개수를 출력한다.

 

이 문제는 절대로 완탐으로 풀면 안된다.

왜냐하면 시간 초과가 발생하기 때문이다.ㅎㅎ

 

그럼 어떻게 해야할까?

바로 다이나믹 프로그래밍 즉, 동적 계획법으로 풀어야 한다.

나는 이용어가 익숙하지 않으므로..ㅜㅜ 내 나름대로 이유를 들어 설명하면

중복되는 코드를 제거하는 알고리즘? 방법?이라고 생각한다. (모든 dp가 이렇지는 않지만... 내 수준에서는 이렇다.)

 

이 문제 같은 경우에도

이걸 완탐으로 푼다고 생각하자.

그러면 dfs로 풀게될것 이고...

dx = {} dy = {} 를 지정해서 풀게 될게 뻔하다.

그러면 이동하면서 그 값이 그전과 값과 큰지 아닌지 확인해야한다.

만약 크다면 그 값으로 바꾸고 아니라면 바꾸면 안된다.

이 짓을 배열끝까지 갈때까지 반복해야 한다.

근데 문제는 같던곳을 또 반복하게 된다.

이 짓을 최소화 할 수 있는 방법이 있을까?

 

그래서

 

#include <bits/stdc++.h>
using namespace std;

int n,m;  

int arr[1010][1010];

int main(void) {    
  ios_base::sync_with_stdio(false); 
  cin.tie(NULL);

  cin >> n >> m;

  int temp; 
  arr[0][0] = 0;
  for(int i = 1;i <=n;i++) {
    for(int j = 1;j<=m;j++) {  
       
       cin >> temp;
       int mx = -1;
       mx  = max(mx,
             max(arr[i-1][j-1],
             max(arr[i-1][j],arr[i][j-1]))); 
       
       arr[i][j] = temp + mx; 
    }
  }


  cout << arr[n][m];


  
}

 

코드를 이렇게 만들었다.

arr[0][0] 는 딱히 이유없지만,.. 그냥 넣었다.ㅎㅎ 

1부터 시작하는 이유는 만약 0부터 시작하면 -1도 포함되어지기 때문이다.

 

저런 식이 가능한 이유는

문제에서

더보기

준규가 (r, c)에 있으면, (r+1, c), (r, c+1), (r+1, c+1)로 이동할 수 있고, 각 방을 방문할 때마다 방에 놓여져있는 사탕을 모두 가져갈 수 있다.

라는 것으로 봤을때.

준규가  (2,2)에 있다면 3,2 / 2,3 / 3,3으로 갈 수 있다는 뜻으로 해석된다.

그러면 준규는 어디에서 왔을까?

저 위 식에 하나라도 만족하면 된다.

아마 1,2가 아닐까? 1,2같은 경우는 첫번째 식에 적용된다.

이런식으로 계산하면 (1,2) // (2,1) // (1,1)에서 왔다는 것을 예측할 수 있다.

 

문제는 최대값을 구하는 문제다.

그렇기 때문에 저 값들중에서 가장 큰 값을 준규가 가져가면 되지 않을까?

 

준규는 항상 최댓값만 가져가기 때문에 중복의 위험도 없어진다.

왜냐하면 항상 계산된 결과를 불러오기 때문이다.

 

위 식에서 mx가 중요한데..

만약, 이게 밖에 있으면 정상적으로 동작하지 않는다.ㅜㅜ;;

 

솔직히 dp는 어렵다.

한 가지 방법론이 있으면 또다른 방법이 있고,,ㅜㅜ;;

#include <stdio.h>
#include <algorithm>
using namespace std;
int D[1001][1001];
int candy[1001][1001];
int max3(int a, int b, int c) {
	return max(max(a, b), c);
}
int main(void) {
	int N, M;
	scanf("%d %d", &N, &M);
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++)
			scanf("%d", &candy[i][j]);
	}
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++)
			D[i][j] = max3(D[i - 1][j], D[i][j - 1], D[i - 1][j - 1]) + candy[i][j];		
	}
	printf("%d", D[N][M]);
}

 

반응형

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

[백준] 1992번 쿼드트리  (0) 2020.06.28
[백준] 14888번 연산자 끼워넣기  (0) 2020.06.27
[백준] 6588번 골드바흐의 추측  (0) 2020.06.25
[백준] 1049번 기타줄  (0) 2020.06.22
[백준] 9625번 BABB번  (0) 2020.06.21

댓글

Designed by JB FACTORY