본문 바로가기
PS/BOJ

백준 1866 / C++

by jaehoonChoi 2022. 8. 18.

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

 

1866번: 택배

첫째 줄에 배송해야 할 물품의 개수 N이 주어진다. (1 ≤ N ≤ 3,000) 둘째 줄에는 각 물품의 목적 지점의 번호가 빈 칸을 사이에 두고 주어진다. 지점의 번호는 10,000 이하의 자연수이다. 셋째 줄에

www.acmicpc.net

 

[ 풀이 ] 

관찰을 통해 인접한 값들끼리, 그리고 그 거리들이 멀수록 헬기로 옮기는게 좋음을 알 수 있다. 

정렬한 후 앞에서부터 트럭으로 옮길지 헬기로 옮길지 정해주자.

또한 옮기는 위치도 결정해줄 수 있다. 

d1, d2 , .... , di를 골라서 옮겼다고 할 때 헬스가 x지점에 내려주면 트럭으로 움직여야 하는 거리는

f(x)=sum(|x-d_i|)가 된다. 이 함수는 중간지점에서 최솟값을 갖는 사실은 잘 알려져 있다. 

dp[i]를 i번째까지 옮긴 최소비용이라 하자.

1. dp[i]=dp[i-1]+T*a[i]: 이건 트럭으로 그냥 옮긴 것이다.

2. j<i에 대해 dp[j]까진 트럭으로, j+1부터 i까진 헬기로 옮기는 것이다.

2번에서 j+1~i번의 절댓값 함수를 처리할때 누적합으로 O(1)에 해주자. O(N^2)에 문제를 풀 수 있다. 

 

[ Code ] 

#include <bits/stdc++.h>
using namespace std;
int n, T, H, dp[3003], a[3003], psum[3003];

// |x-a[s+1]|+...+|x-a[e]| min : x=a[(s+e+1)/2] 일 때 
int func(int s, int e) {
	int mid = (s + e + 1) >> 1;
	return T * ((2 * mid - s - e) * a[mid] + psum[s] + psum[e] - 2 * psum[mid]);
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++)cin >> a[i];
	sort(a + 1, a + n + 1);
	for (int i = 1; i <= n; i++) {
		psum[i] = psum[i - 1] + a[i];
	}
	cin >> T >> H;
	// dp
	for (int i = 1; i <= n; i++) {
		dp[i] = dp[i - 1] + T * a[i];
		for (int j = 0; j < i; j++) {
			dp[i] = min(dp[i], dp[j] + func(j, i) + H);
		}
	}
	cout << dp[n];
}

'PS > BOJ' 카테고리의 다른 글

백준 14958 / C++  (0) 2022.08.22
백준 3037 / C++  (0) 2022.08.22
백준 5463 / C++  (0) 2022.08.17
백준 1017 / C++  (0) 2022.08.17
백준 9525 / C++  (0) 2022.08.17

댓글