더 이상 tistory 블로그를 운영하지 않습니다. glanceyes.github.io에서 새롭게 시작합니다.

새소식

알고리즘/BOJ 풀이

BOJ 백준 2184번 김치배달

  • -

BOJ 백준 2184 김치배달

문제: www.acmicpc.net/problem/2184

 

2184번: 김치 배달

첫째 줄에 두 정수 N, L이 주어진다. L은 김치 공장의 x좌표이다. 다음 N개의 줄에는 김치를 배달할 도시의 x좌표가 주어진다. 모든 좌표는 1이상 1,000,000이하의 정수이다.

www.acmicpc.net

김치 N 개를 N 개의 도시들에 배달하는데, 김치 공장과 각각의 도시들은 1차원 직선상의 점에 위치해 있다. 이 좌표계의 좌표 값은 정수임을 전제로 한다.

 

김치를 각 도시에 배달하면서 1차원 직선을 따라 1초에 한 칸씩 움직일 수 있고, 김치는 1초에 1만큼씩 쉬게 된다. 그리고 각 도시에 도착하는 그 순간 김치가 배달되는 것으로 가정한다. 즉, 어떤 도시에 도착하는 순간 해당 도시로 김치 배달이 완료된다. 각 도시에 김치가 도착했을 때의 김치의 쉰 정도의 합의 최솟값을 구하는 것이 이 문제의 목표이다.

 

 

 

김치 공장 위치를 기준으로 양옆을 왔다 갔다 하며 또는 한쪽 방향으로만 계속 이동하는 특징을 보이는데, 이러한 문제는 Dynamic programming으로 해결할 수 있다. 그리고 이 문제처럼 1차원 좌표계를 좌우로 움직이면서 주어진 모든 좌표나 위치에 도달했을 때 구할 수 있는 value의 최솟값 또는 최댓값을 구하는 문제 유형은 종종 보인다. 주목해야 할 점은 어느 한 지점 A에서 다른 지점 B로 이동할 때 A와 B 사이에 있는 지점들은 모두 방문을 한 것으로 처리해야 최솟값을 얻을 수 있다. 그러므로 김치 배달원이 배달한 도시들은 항상 연속적인 범위를 갖는다.

 

 

dp[left][right][where]: left부터 right까지 이 범위에 있는 도시들에 배달한 상태에서, 현재 배달원이 where에 있을 때 김치 쉰 정도 합의 최솟값
where: 현재 배달원이 left에 있는지 (where 값이 0인 경우), right에 있는지 (where 값이 1인 경우)

 

 

각 도시에 배달할 때마다 아직 배달을 완료하지 않은 남은 도시들로 배달해야 하는 김치들의 쉰 정도가 각각 누적되기 때문에 남은 도시들의 개수도 고려해 줘야 한다. 그러나 이는 이제까지 배달을 완료한 도시 범위만 알면 남은 도시들은 자연적으로 구할 수 있으므로 이를 또 다른 상태로 기억해야 할 필요는 없다.

 

 

num(남은 도시의 개수): (n + 1) - (right - left + 1)

 

 

 

코드 구현이 좀 더 수월하도록 공장도 방문하는 도시의 일부로 포함하기로 전제했다.

 

 

 

1) 배달원이 현재 배달 완료한 도시 범위에서 가장 왼쪽에 위치할 때

 

(1) 현재 있는 도시에서 바로 왼쪽에 있는 도시로 이동

 

dp[left][right][0] = dp[left - 1][right][0] + num * (pos[left] - pos[left - 1])

 

 

(2) 배달 완료한 가장 오른쪽의 도시에서 바로 오른쪽에 있는 도시로 이동

 

dp[left][right][0] = dp[left][right + 1][1] + num * (pos[right + 1] - pos[left])

 

 

 

2) 배달원이 현재 배달 완료한 도시 범위에서 가장 오른쪽에 위치할 때

 

(1) 현재 있는 도시에서 바로 오른쪽에 있는 도시로 이동

 

dp[left][right][1] = dp[left][right + 1][1] + num * (pos[right + 1] - pos[right])

 

 

(2) 배달 완료한 가장 왼쪽의 도시에서 바로 왼쪽에 있는 도시로 이동

 

dp[left][right][1] = dp[left - 1][right][0] + num * (pos[right] - pos[left - 1])

 

 

 

#include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std; const int N_MAX = 1000; const int INF = 0x3f3f3f3f; int n, l; vector<int> pos, sum; int dp[N_MAX + 1][N_MAX + 1][2]; int go(int left, int right, int where){ if (left == 0 && right == n) { return 0; } int& ret = dp[left][right][where]; if (ret != -1){ return ret; } ret = INF; if (where == 0){ if (left - 1 >= 0){ ret = min(ret, go(left - 1, right, 0) + (pos[left] - pos[left - 1]) * (n + 1 - (right - left + 1))); } if (right + 1 <= n){ ret = min(ret, go(left, right + 1, 1) + (pos[right + 1] - pos[left]) * (n + 1 - (right - left + 1))); } } else { if (left - 1 >= 0) { ret = min(ret, go(left - 1, right, 0) + (pos[right] - pos[left - 1]) * (n + 1 - (right - left + 1))); } if (right + 1 <= n){ ret = min(ret, go(left, right + 1, 1) + (pos[right + 1] - pos[right]) * (n + 1 - (right - left + 1))); } } return ret; } int main(){ scanf("%d %d", &n, &l); memset(dp, -1, sizeof(dp)); pos.push_back(l); for (int i = 0; i < n; i++){ int x; scanf("%d", &x); pos.push_back(x); } sort(pos.begin(), pos.end()); int start = 0; for (int i = 0; i <= n; i++){ if (pos[i] == l){ start = i; } } printf("%d\n", go(start, start, 0)); return 0; }
Contents

글 주소를 복사했습니다

부족한 글 끝까지 읽어주셔서 감사합니다.
보충할 내용이 있으면 언제든지 댓글 남겨주세요.