UVA 1169 Robotruck 单调队列优化 DP

来源:互联网 发布:网络销售平台搭建方案 编辑:程序博客网 时间:2024/05/17 22:01

题意:在平面上有N个垃圾,告诉每个垃圾的坐标。现在有一个机器人从原点出发,按照给定的顺序把垃圾捡回来。同时每个垃圾都有重量,机器人有最大装载重量C。垃圾之间和垃圾和原点之间的距离定义为两点坐标的曼哈顿距离。现在求最少的距离,使机器人完成这件任务。

思路:看到N=100000,就该去想O(N)的算法了。这里我们用DP来求解。

            设dp[i]表示捡完前i个垃圾,并回到原点的最少距离。

            我们可以得到递推式:dp[i] = min(dp[k] - dis[k] + ds[i] - ds[k] + dis[i]), ws[i] - ws[k] <= C,其中dis[i]表示第i个垃圾到原点的距离,ds[i]表示前i个垃圾的距离的和,ws[i]表示前i个垃圾的总重量。

          我们可以看到,dis[i],ds[i]是和k无关的项,变形得:dp[i] = min(dp[k] - dis[k] - ds[k]) + ds[i] + dis[i] ,ws[i] -ws[k] <= C.这就转化成了求前面一项的最小值。再次,我们发现,前面一项也只是和k有关,而对于固定的k,这也是个定值。这样,我们就能用单调队列优化,在队列的头保存最小值。

代码如下:

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 100100;int x[MAXN], y[MAXN], w[MAXN];int dist[MAXN], sumw[MAXN], dis[MAXN];int q[MAXN], dp[MAXN];int func(int i){return dp[i] - dist[i + 1] + dis[i + 1];}int main(){//freopen("input.txt", "r", stdin);int T;int C, N, head, tail;scanf("%d", &T);while (T--){scanf("%d %d", &C, &N);dist[0] = dis[0] = 0;for (int i = 1; i <= N; i++){scanf("%d %d %d", &x[i], &y[i], &w[i]);dist[i] = dist[i - 1] + abs(x[i] - x[i - 1]) + abs(y[i] - y[i - 1]);dis[i] = abs(x[i]) + abs(y[i]);sumw[i] = sumw[i - 1] + w[i];}head = tail = 0;q[tail++] = 0; for (int i = 1; i <= N; i++){while (head + 1 < tail && sumw[i] - sumw[q[head]] > C)head++;dp[i] = func(q[head]) + dis[i] + dist[i];while (head + 1 < tail && func(i) <= func(q[tail-1]))tail--;q[tail++] = i;}//for (int i = 1; i <= N; ++i)printf("%d\n", dp[N]);if (T)puts("");}return 0;}


0 0
原创粉丝点击