题目链接:uva 1169 - Robotruck
题目大意:给出W和n,W表示机器人的限载重量,n表示有n个垃圾,然后给出n个垃圾的坐标和重量,要求清理垃圾按照垃圾的序号从小到大,机器人可以一次清理多个垃圾,只要重量不大于W,位于原点有垃圾桶,现在机器人从原点出发,要求清理完所有的垃圾的曼哈顿距离最小。
解题思路:dp[i]表示清理完i号垃圾返回原点的最短曼哈顿距离,d[i]表示从1一直按照序号移动到i的距离和,w[i]表示1到i的垃圾重量和,o[i]表示垃圾距离原点的距离。dp[i] = min{f(j) + d[i] + o[i] | j < i && w[i]-w[j] ≤ W};
f(x) = dp[x] - o[x+1] - d[x+1].
单调队列可以进行优化,序列按照f(x)的大小排序,每次保证考虑的i可以迅速找到最小的f(x)。
#include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <queue> using namespace std; const int N = 1e5+10; int n, d[N], w[N], o[N], W, dp[N]; int x[N], y[N]; int distant(int xi, int yi) { return abs(xi) + abs(yi); } void init() { int wi; scanf("%d%d", &W, &n); d[0] = w[0] = 0; for (int i = 1; i <= n; i++) { scanf("%d%d%d", &x[i], &y[i], &wi); d[i] = d[i-1] + distant(x[i] - x[i-1], y[i] - y[i-1]); o[i] = distant(x[i], y[i]); w[i] = w[i-1]+wi; } } int f(int x) { return dp[x-1] + o[x] - d[x]; } int solve() { deque<int> que; que.push_back(0); for (int i = 1; i <= n; i++) { while (!que.empty() && w[i] - w[que.front()] > W) que.pop_front(); dp[i] = f(que.front()+1) + d[i] + o[i]; while (!que.empty() && f(i+1) <= f(que.back()+1)) que.pop_back(); que.push_back(i); } return dp[n]; } int main () { int cas; scanf("%d", &cas); while (cas--) { init(); printf("%d\n", solve()); if (cas) printf("\n"); } return 0; }