※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 2618번 문제인 경찰차이다.
문제는 아래 링크를 확인하자.

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

 

2618번: 경찰차

첫째 줄에는 동서방향 도로의 개수를 나타내는 정수 N(5 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 처리해야 하는 사건의 개수를 나타내는 정수 W(1 ≤ W ≤ 1,000)가 주어진다. 셋째 줄부터 (W+2)번째 줄

www.acmicpc.net

dp[x][y]를 (1번 경찰차가 마지막으로 처리한 사건이 x, 2번 경찰차가 마지막으로 처리한 사건이 y)인 경우의 최소 이동거리라 하자. 이 때 dp값은 이 값은 x>y+1인 경우 dp[x-1][y] + (1번 경찰차가 x-1에서 x까지 이동한 거리), y>x+1인 경우 dp[x][y-1] + (2번 경찰차가 y-1에서 y까지 이동한 거리)로 계산할 수 있다. x=y+1인 경우에는 dp[i][y]의 최솟값(단, i는 y미만), y = x+1인 경우에는 dp[x][i]의 최솟값(단, i는 x 미만)이 된다. x와 y가 같은 경우는 존재할 수 없다.

 

위의 점화식을 이용해 문제를 해결하자. 어떤 경찰차를 실제로 움직였는지 역추적하는 과정은 위 계산을 진행하면서 각 과정의 최적해가 어떤 이전 단계로부터 왔는지를 별도의 배열에 저장하는 것으로 간단히 구현할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
using namespace std;

int N, W;
int dp[1001][1001]; // dp[x][y]: 1번 경찰차가 마지막으로 처리한 사건은 x, 2번 경찰차가 마지막으로 처리한 사건은 y
pair<int,int> backtrack[1001][1001];
bool visited[1001][1001];
int R1[1001], C1[1001], R2[1001], C2[1001];

int dist1(int i, int j) {
	return abs(R1[i] - R1[j]) + abs(C1[i] - C1[j]);
}

int dist2(int i, int j) {
	return abs(R2[i] - R2[j]) + abs(C2[i] - C2[j]);
}

int func(int x, int y) {
	int& ret = dp[x][y];
	if (visited[x][y]) return ret;
	visited[x][y] = 1;

	if (x > y + 1) ret = func(x - 1, y) + dist1(x - 1, x), backtrack[x][y] = make_pair(x - 1, y);
	else if (x + 1 < y) ret = func(x, y - 1) + dist2(y - 1, y), backtrack[x][y] = make_pair(x, y - 1);
	else {
		ret = 2000000007;
		if (x > y) {
			for (int i = 0; i < y; i++) {
				int val = func(i, y) + dist1(i, x);
				if (val < ret) ret = val, backtrack[x][y] = make_pair(i, y);
			}
		}
		else {
			for (int i = 0; i < x; i++) {
				int val = func(x, i) + dist2(i, y);
				if (val < ret) ret = val, backtrack[x][y] = make_pair(x, i);
			}
		}
	}

	return ret;
}

int ans = 2000000007, ansx, ansy;
vector<int> stk;

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

	cin >> N >> W;
	for (int i = 1; i <= W; i++) {
		cin >> R1[i] >> C1[i];
	}
	for (int i = 1; i <= W; i++) R2[i] = R1[i], C2[i] = C1[i];
	R1[0] = C1[0] = 1, R2[0] = C2[0] = N;
	
	dp[1][0] = dist1(0, 1), dp[0][1] = dist2(0, 1);
	visited[1][0] = visited[0][1] = 1;
	backtrack[1][0] = backtrack[0][1] = make_pair(0, 0);

	for (int i = 0; i < W; i++) {
		int val = func(i, W);
		if (val < ans) ans = val, ansx = i, ansy = W;
		val = func(W, i);
		if (val < ans) ans = val, ansx = W, ansy = i;
	}
	
	while (ansx + ansy) {
		if (ansx > ansy) stk.emplace_back(1);
		else stk.emplace_back(2);

		int nxtx = backtrack[ansx][ansy].first, nxty = backtrack[ansx][ansy].second;
		ansx = nxtx, ansy = nxty;
	}

	cout << ans << '\n';
	while (!stk.empty()) {
		cout << stk.back() << '\n';
		stk.pop_back();
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 27660 // C++] Queue skipping (Hard)  (0) 2023.03.11
[BOJ 4883 // C++] 삼각 그래프  (0) 2023.03.10
[BOJ 2116 // C++] 주사위 쌓기  (0) 2023.03.10
[BOJ 25378 // C++] 조약돌  (0) 2023.03.09
[BOJ 27866 // C++] 문자와 문자열  (0) 2023.03.09

+ Recent posts