※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 2518번 문제인 회전 테이블이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/2518
2518번: 회전 테이블
첫째 줄에는 요리의 개수를 나타내는 정수 N (3 ≤ N ≤ 300,000)이 주어진다. N은 항상 3의 배수이다. 둘째 줄부터 넷째 줄에는 아빠, 엄마, 현이 순서대로 각 줄마다 한 사람씩 먹고 싶어 하는 요리
www.acmicpc.net
편의상 요리의 인덱스를 문제와 같은 1-based가 아닌 0-based를 기준으로 풀겠다.
먼저 "엄마"와 "현이"가 자신이 먹고싶은 음식이 본인 앞에 있을 때의 상황을 그 때 "아빠" 앞에 놓인 요리의 번호로 나타내자. 이렇게 인덱스의 기준을 통일시키면 앞으로의 구현에서 혼동이 적게 된다.
이제, dp[x][y][z][i] 을 ("아빠"가 x번 요리까지, "엄마"가 y번 요리까지, "현이"가 z번 요리까지 순서대로 먹은 상태 가운데 마지막으로 음식을 먹은 사람이 i=0이면 "아빠", i=1이면 "엄마", i=2이면 "현이"를 만족하는 식사방식 중 중 테이블 회전횟수의 최솟값) 으로 정의하자. 이 때 i=0이면 dp[x][y][z][i]는 dp[x-1][y][z][0], dp[x-1][y][z][1], dp[x-1][y][z][2] 세 값을 이용해 계산할 수 있음을 알 수 있다. 이와 비슷하게 i=1, i=2인 경우 또한 앞선 dp값을 이용해 계산해낼 수 있음을 관찰할 수 있다. (단, i에 대응되는 사람이 주어진 상태에서 마지막으로 식사를 할 수 없는 경우 테이블의 회전횟수를 무한대와 같이 취급해주자. 또한 아직 아무도 식사를 하지 않은 dp[0][0][0][0], dp[0][0][0][1], dp[0][0][0][2]의 경우 적절하게 초기값을 넣어주자.)
위와 같은 점화관계를 이용해 문제를 해결하자. 시간복잡도는 각자가 먹고싶은 요리개수의 최댓값을 P라 할 때
아래는 제출한 소스코드이다.
#include <iostream>
using namespace std;
int N, X, Y, Z;
int arrX[101], arrY[101], arrZ[101];
int dp[101][101][101][3];
bool visited[101][101][101][3];
int dist(int x, int y) {
int ret = abs(x - y);
return min(ret, N - ret);
}
int func(int x, int y, int z, int i) {
int& ret = dp[x][y][z][i];
if (visited[x][y][z][i]) return ret;
visited[x][y][z][i] = 1;
ret = 1000000007;
if (i == 0) {
if (x) {
ret = min(ret, func(x - 1, y, z, 0) + dist(arrX[x - 1], arrX[x]));
ret = min(ret, func(x - 1, y, z, 1) + dist(arrY[y], arrX[x]));
ret = min(ret, func(x - 1, y, z, 2) + dist(arrZ[z], arrX[x]));
}
}
else if (i == 1) {
if (y) {
ret = min(ret, func(x, y - 1, z, 0) + dist(arrX[x], arrY[y]));
ret = min(ret, func(x, y - 1, z, 1) + dist(arrY[y - 1], arrY[y]));
ret = min(ret, func(x, y - 1, z, 2) + dist(arrZ[z], arrY[y]));
}
}
else {
if (z) {
ret = min(ret, func(x, y, z - 1, 0) + dist(arrX[x], arrZ[z]));
ret = min(ret, func(x, y, z - 1, 1) + dist(arrY[y], arrZ[z]));
ret = min(ret, func(x, y, z - 1, 2) + dist(arrZ[z - 1], arrZ[z]));
}
}
return ret;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> N;
cin >> X;
for (int x = 1; x <= X; x++) {
cin >> arrX[x];
arrX[x]--;
}
cin >> Y;
for (int y = 1; y <= Y; y++) {
cin >> arrY[y];
arrY[y]--;
arrY[y] -= N / 3;
if (arrY[y] < 0) arrY[y] += N;
}
cin >> Z;
for (int z = 1; z <= Z; z++) {
cin >> arrZ[z];
arrZ[z]--;
arrZ[z] += N / 3;
if (arrZ[z] >= N) arrZ[z] -= N;
}
dp[0][0][0][1] = dp[0][0][0][2] = N / 3;
visited[0][0][0][0] = visited[0][0][0][1] = visited[0][0][0][2] = 1;
cout << min(func(X, Y, Z, 0), min(func(X, Y, Z, 1), func(X, Y, Z, 2)));
}
'BOJ' 카테고리의 다른 글
[BOJ 4540 // C++] Q (0) | 2023.02.24 |
---|---|
[BOJ 27541 // C++] 末尾の文字 (Last Letter) (0) | 2023.02.24 |
[BOJ 2528 // C++] 사다리 (0) | 2023.02.23 |
[BOJ 24314 // C++] 알고리즘 수업 - 점근적 표기 2 (0) | 2023.02.23 |
[BOJ 27494 // C++] 2023년은 검은 토끼의 해 (0) | 2023.02.23 |