mojo's Blog

[백준 10251] 운전 면허 시험 본문

백준/Dynamic Programming

[백준 10251] 운전 면허 시험

_mojo_ 2021. 12. 6. 15:03

문제 링크 => 10251번: 운전 면허 시험 (acmicpc.net)

 

10251번: 운전 면허 시험

만일 G 이하의 연료량으로 s에서 t까지 가는 것이 가능하다면 가능한 한 빨리 도착했을 때 걸리는 시간을, 불가능하다면 -1을 출력한다.

www.acmicpc.net

 

다이나믹 프로그래밍 문제이다.

 

아무래도 여러번 recursion을 이용한 memoziation 기법을 이용해서 해결하려고 했으나 시간초과가 계속 뜬다.

그래서 4차원 배열을 설정하여 다음과 같이 해결하였다.

 

dp(curX, curY, turn, direction) = (curX, curY) 에서 turn 번 회전하여 direction 방향을 바라볼 때의 최소 연료량

 

먼저 시작지점에서부터 오른쪽 방향, 아래쪽 방향으로 가는 것은 회전하는 것이 상관 없으므로 이 경우에 대한

테이블을 먼저 채워주고 그 이후에는 다음과 같은 방법으로 테이블을 채웠다.

 

(1) dp(curX, curY, turn, RIGHT) 일 경우 (오른쪽 방향)

     => (curX - 1, curY) 위치에서 (turn - 1) 번 회전했을 때 DOWN 방향에서 들어오는 총 연료량과

           (curX, curY - 1) 위치에서 turn 번 회전할 때 RIGHT 방향에서 들어오는 총 연료량의 최솟값이다.

 

dp[i][j][t][RIGHT]

= min({ dp[i - 1][j][t - 1][DOWN] + down_way[i - 1][j], dp[i][j - 1][t][RIGHT] + right_way[i][j - 1] });

 

 

(2) dp(curX, curY, turn, DOWN) 일 경우 (아랫 방향)

=> (curX - 1, curY) 위치에서 turn 번 회전했을 때 DOWN 방향에서 들어오는 총 연료량과

      (curX, curY - 1) 위치에서 (turn - 1) 번 회전할 때 RIGHT 방향에서 들어오는 총 연료량의 최솟값이다.

 

dp[i][j][t][DOWN]

= min({ dp[i - 1][j][t][DOWN] + down_way[i - 1][j], dp[i][j - 1][t - 1][RIGHT] + right_way[i][j - 1] });

 

 

Solution Code

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>

using namespace std;

int right_way[101][101], down_way[101][101];
int dp[101][101][201][2];
int Row, Col, L, G;
const int RIGHT = 0, DOWN = 1, INF = 1000000000;

int solution()
{
	int min_turn = INF, result;

	// dp(curX, curY, turn_cnt, direction) 
	dp[0][0][0][RIGHT] = dp[0][0][0][DOWN] = 0;
	// 오른쪽
	for (int i = 1; i < Col; i++) {
		dp[0][i][0][RIGHT] = dp[0][i - 1][0][RIGHT] + right_way[0][i - 1];
		dp[0][i][1][DOWN] = dp[0][i - 1][0][RIGHT] + right_way[0][i - 1];
	}
	// 왼쪽
	for (int i = 1; i < Row; i++) {
		dp[i][0][0][DOWN] = dp[i - 1][0][0][DOWN] + down_way[i - 1][0];
		dp[i][0][1][RIGHT] = dp[i - 1][0][0][DOWN] + down_way[i - 1][0];
	}

	// dynamic programming
	for (int i = 1; i < Row; i++) {
		for (int j = 1; j < Col; j++) {
			for (int t = 1; t < Row + Col; t++) {
				dp[i][j][t][RIGHT] = min({ dp[i - 1][j][t - 1][DOWN] + down_way[i - 1][j],
					dp[i][j - 1][t][RIGHT] + right_way[i][j - 1] });
				dp[i][j][t][DOWN] = min({ dp[i - 1][j][t][DOWN] + down_way[i - 1][j],
					dp[i][j - 1][t - 1][RIGHT] + right_way[i][j - 1] });
			}
		}
	}

	for (int t = 0; t < Row + Col; t++) {
		if (dp[Row - 1][Col - 1][t][RIGHT] <= G) {
			min_turn = min(min_turn, t);
		}
		if (dp[Row - 1][Col - 1][t][DOWN] <= G) {
			min_turn = min(min_turn, t);
		}
	}

	result = min_turn + L * (Row + Col - 2);
	return result >= INF ? -1 : result;
}

void set_drive()
{
	int i, j;

	scanf("%d %d %d %d", &Row, &Col, &L, &G);
	for (i = 0; i < Row; i++) {
		for (j = 0; j < Col - 1; j++) {
			scanf("%d", &right_way[i][j]);
		}
	}
	for (i = 0; i < Row - 1; i++) {
		for (j = 0; j < Col; j++) {
			scanf("%d", &down_way[i][j]);
		}
	}
}

void initialize()
{
	int i, j, k;
	for (i = 0; i <= Row; i++) {
		for (j = 0; j <= Col; j++) {
			for (k = 0; k <= 200; k++) {
				dp[i][j][k][DOWN] = dp[i][j][k][RIGHT] = INF;
			}
		}
	}
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--) {
		set_drive();
		initialize();
		printf("%d\n",solution());
	}

	return 0;
}

 

'백준 > Dynamic Programming' 카테고리의 다른 글

[백준 2342] Dance Dance Revolution  (0) 2021.12.28
[백준 1509] 팰린드롬 분할  (0) 2021.12.23
[백준 1937] 욕심쟁이 판다  (0) 2021.11.15
[백준 10942] 팰린드롬?  (0) 2021.11.07
[백준 1958] LCS 3  (0) 2021.11.06
Comments