본문 바로가기

알고리즘/algospot

동적 계획법(Dynamic Programming)

동적 계획법중복되는 부분 문제의 값(계산 결과)을 메모리(cache)에 저장재활용하는 방법

메모리제이션 구현 패턴

int cache[2500][2500];
int someObscureFunction(int a, int b) {
	// basecase
	if (...) return ...;

	// cache에 저장된 값이 있으면 바로 리턴(cache는 -1로 초기화되어있음)
	int& ret = cache[a][b];
	if (ret != -1) return ret;

	// 답 계산
	...

	return ret;
}
  • 기저사례 가장 먼저 처리
  • cache배열 초기화(memset 함수 사용 가능)
  • cache배열에 대한 참조형 변수 ret 사용
    - ret가 바뀌면 cache배열도 바뀜 → cache가 다차원 배열일 때 인덱스 순서를 바꿔쓰는 실수를 막을 수 있음
  • 완전 탐색으로 해결 한 후, 중복된 부분 문제는 한 번만 계산하도록 메모리제이션 적용 가능

 

예제) JUMPGAME

링크 : https://www.algospot.com/judge/problem/read/JUMPGAME

 

algospot.com :: JUMPGAME

외발 뛰기 문제 정보 문제 땅따먹기를 하다 질린 재하와 영훈이는 땅따먹기의 변종인 새로운 게임을 하기로 했습니다. 이 게임은 그림과 같이 n*n 크기의 격자에 각 1부터 9 사이의 정수를 쓴 상

www.algospot.com

문제

땅따먹기를 하다 질린 재하와 영훈이는 땅따먹기의 변종인 새로운 게임을 하기로 했습니다. 이 게임은 그림과 같이 n*n 크기의 격자에 각 1부터 9 사이의 정수를 쓴 상태로 시작합니다. 각 차례인 사람은 맨 왼쪽 윗 칸에서 시작해 외발로 뛰어서 오른쪽 아래 칸으로 내려가야 합니다. 이 때 각 칸에 적혀 있는 숫자만큼 오른쪽이나 아래 칸으로 움직일 수 있으며, 중간에 게임판 밖으로 벗어나면 안 됩니다.

균형을 잃어서 다른 발로 서거나 넘어져도 게임에서 집니다만, 재하와 영훈이는 젊고 활기차기 때문에 외발로 뛰어다니는 것은 아무것도 아닙니다. 다만 걱정되는 것은 주어진 게임판에 시작점에서 끝점으로 가는 방법이 존재하지 않을 수도 있다는 것입니다. 예를 들어 그림 (a)의 게임판에서는 사각형으로 표시된 칸들을 통해 끝에 도달할 수 있지만, 숫자가 하나 바뀐 그림 (b)에서는 그럴 수가 없습니다.

게임판이 주어질 때 왼쪽 위의 시작점에서 오른쪽 아래의 시작점에 도달할 수 있는 방법이 있는지 확인하는 프로그램을 작성하세요.

입력

입력의 첫 줄에는 테스트 케이스의 수 C(C <= 50)가 주어집니다. 각 테스트 케이스의 첫 줄에는 격자의 크기 n(2 <= n <= 100)이 주어지고, 그 후 n줄에 각 n개의 숫자로 왼쪽 위부터 각 칸에 쓰인 숫자들이 주어집니다. 오른쪽 아래 있는 끝 점 위치에는 0이 주어집니다.

출력

각 테스트 케이스마다 한 줄로, 시작점에서 끝 점으로 도달할 수 있을 경우 "YES"를, 아닐 경우 "NO"를 출력합니다. (따옴표 제외)

문제 풀이

  • 게임판의 같은 위치를 여러번 탐색할 가능성 있으므로 메모리제이션 사용
  • cache는 -1로 초기화
  • 해당 위치에서 게임판의 끝에 도달하는 것이 불가능 한 경우 cache에 0 저장

풀이 코드

// 동적 계획법
// 32ms
#include <iostream>
#include <string.h>
using namespace std;

int cache[100][100];
int board[100][100];
int bsize;

int jumpgame(int y, int x) {
	// basecase
	if (y == bsize - 1 && x == bsize - 1) return 1;

	int& ret = cache[y][x];
	if (ret != -1) return ret;

	// y축 방향
	if (y + board[y][x] < bsize)
		ret = jumpgame(y + board[y][x], x);
	// x축 방향
	if (x + board[y][x] < bsize && ret != 1) {
		ret = jumpgame(y, x + board[y][x]);
		if (ret != 1) ret = 0;
	}
	return ret;
}
int main() {
	int C;
	
	cin >> C;
	for (int i = 0; i < C; i++) {
		memset(cache, -1, sizeof(cache));
		cin >> bsize;
		for (int j = 0; j < bsize; j++) {
			for (int k = 0; k < bsize; k++) {
				cin >> board[j][k];
			}
		}
		int ret = jumpgame(0, 0);
		if (ret == 0) cout << "NO" << endl;
		else cout << "YES" << endl;
	}
}

 

 

출처 : 알고리즘 문제해결전략

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

[C++]algospot QUADTREE  (0) 2021.08.17
분할 정복  (0) 2021.08.11
[C++]algospot CLOCKSYNC  (0) 2021.07.26
[C++]algospot BOARDCOVER  (0) 2021.07.25
[C++]algospot PICNIC  (0) 2021.07.22