컴퓨터 사이언스/1고리즘

백준 2096 : 내려가기

저세상 개발자 2021. 8. 17. 00:27

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

 

2096번: 내려가기

첫째 줄에 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 N개의 줄에는 숫자가 세 개씩 주어진다. 숫자는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 중의 하나가 된다.

www.acmicpc.net

 

쉬운 DP문제다. 최대 숫자 30만개를 입력받아야하므로 메모리 제한 4mb이 빡센데, 일반적인 dp를 풀듯이 갱신하지 말고 갱신하고자 하는 줄과 바로 그 직전 줄만 보면 메모리 제한에 걸리지 않고 문제를 해결할 수 있다.

 

0. 이전에 수행한 연산이 이후의 연산에 영향을 미치므로 DP문제다.

1. 현재 줄을 갱신할 때는 (현재 위치에 있는 숫자) + (이전 줄에서 현재 위치로 올 수 있는 위치 중에서 가장 큰 값 or 가장 작은 값)을 더해준다.

3. i = 0 부터 n - 1까지 반복해주면 최대값 or 최소값을 구할 수 있다.

 

점화식으로 표현하자면 아래와 같다.

//최대값
A_n[0] = max(A_(n-1)[0], A_(n-1)[1])
A_n[1] = max(A_(n-1)[0], A_(n-1)[1], A_(n-1)[2])
A_n[2] = max(A_(n-1)[1], A_(n-1)[2])

//최소값
A_n[0] = min(A_(n-1)[0], A_(n-1)[1])
A_n[1] = min(A_(n-1)[0], A_(n-1)[1], A_(n-1)[2])
A_n[2] = min(A_(n-1)[1], A_(n-1)[2])

 

점화식에서 아래첨자 n은 n번째 줄을 의미한다. 점화식에서 보이는 것과 같이 n번째 줄을 갱신할 때 바로 직전의 결과(n -1)번째 줄의 결과만이 사용되므로 단순히 int[3] cur 배열과 int[3] prev 배열 두 개 만으로 문제를 해결할 수 있다.

 

초기에 주어지는 최대 30만개의 숫자도 int로 받아도 문제를 해결할 수 있지만, 입력으로 주어지는 수가 0 ~ 9로 1바이트 범위 내에서 서로 식별 가능하기 때문에 1바이트 자료구조인 char 배열로 받아 아스키코드 값을 기준으로 저장해줬다.

 

#include <iostream>

using namespace std;

int n;
char num[100'000][3];

int max(int a, int b, int c) { 
	a = a > b ? a : b;
	a = a > c ? a : c;
	return a;
}
int min(int a, int b, int c) {
	a = a < b ? a : b;
	a = a < c ? a : c;
	return a;
}

int DP(bool flag) {
	int prev[3] = { 0, };
	int cur[3];
	int min_default = 1e9;
	int max_default = 0;

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < 3; j++)
			cur[j] = num[i][j];

		if (flag) {
			cur[0] += min(prev[0], prev[1], min_default);
			cur[1] += min(prev[0], prev[1], prev[2]);
			cur[2] += min(prev[1], prev[2], min_default);
		}
		else {
			cur[0] += max(prev[0], prev[1], max_default);
			cur[1] += max(prev[0], prev[1], prev[2]);
			cur[2] += max(prev[1], prev[2], max_default);
		}

		for (int j = 0; j < 3; j++)
			prev[j] = cur[j];
	}

	if (flag) return min(cur[0], cur[1], cur[2]);
	else return max(cur[0], cur[1], cur[2]);
}

void solution() {
	char tmp;
	cin >> n;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < 3; j++) {
			cin >> tmp;
			num[i][j] = tmp - '0';
		}
	}

	cout << DP(0) << ' ';
	cout << DP(1);
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	solution();

	return 0;
}
메모리: 2312 kb 시간: 8 ms

 

참고로 char배열로 안하고 int배열로 입력받으면 아래와 같이 더 느리고 메모리도 더 많이 먹는다.

메모리: 3192 kb 시간: 20 ms