uva 1169 - Robotruck(dp+单调队列)

题目链接: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;
}


你可能感兴趣的:(uva 1169 - Robotruck(dp+单调队列))