Robotruck UVALive - 3983 捡垃圾的机器人 单调队列优化dp

版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/qq_42835910/article/details/90113643

 题目链接

This problem is about a robotic truck that distributes mail packages to several locations in a factory. The robot sits at the end of a conveyer at the mail office and waits for packages to be loaded into its cargo area. The robot has a maximum load capacity, which means that it may have to perform several round trips to complete its task. Provided that the maximum capacity is not exceeded, the robot can stop the conveyer at any time and start a round trip distributing the already collected packages. The packages must be delivered in the incoming order.

     The distance of a round trip is computed in a grid by measuring the number of robot moves from the mail office, at location (0,0), to the location of delivery of the first package, the number of moves between package delivery locations, until the last package, and then the number of moves from the last location back to the mail office. The robot moves a cell at a time either horizontally or vertically in the factory plant grid. For example, consider four packages, to be delivered at the locations (1,2), (1,0), (3,1), and (3,1). By dividing these packages into two round trips of two packages each, the number of moves in the first trip is 3+2+1=6, and 4+0+4=8 in the second trip. Notice that the two last packages are delivered at the same location and thus the number of moves between them is 0.

     Given a sequence of packages, compute the minimum distance the robot must travel to deliver all packages.

分析:首先设 d[ i ] 为处理到第 i 个垃圾所用的最小距离,那么很容易想到动态转移方程:d[ i ] = min { d[ j ] + dist2origin( j + 1 )  +  dist( j + 1 , i ) + dist2origin( i ) }  且 w( j + 1 , i )  <= W , 解释一下:dist( i )  为 i 点到原点的距离(指哈密顿距离),dist( j + 1 ,i) 代表 从j + 1 到 i 的距离和。w(j + 1 , i ) 为从 j + 1 到 i 的重量和。W 为最大重量。

转化动态方程了:我们用前缀和的思想分别记录前缀距离和前缀重量,分别用数组 total_dist[ i ] ,total_weight[ i ] ,d[ i ] 为点i 到原点的距离,这样方程就可以变为:

                dp[ i ] = min { d[j] - total_dist[j+1] + dist2origin[j+1] } 且 total_weight[ i ] - total_weight[ j ] <= W ;变成这样后你会发现前面的各个数只与本身相关,可以把他们放入一个队列中,只要维护队列的最小值(在重量满足的前提下).

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 100000 + 10;

int x[maxn], y[maxn];
int total_dist[maxn], total_weight[maxn], dist2origin[maxn];
int q[maxn], d[maxn];

int func(int i) {
  return d[i] - total_dist[i+1] + dist2origin[i+1];
}

main() {
  int T, c, n, w, front, rear;
  scanf("%d", &T);
  while(T--) {
    scanf("%d%d", &c, &n);
    total_dist[0] = total_weight[0] = x[0] = y[0] = 0;
    for(int i = 1; i <= n; i++) {
      scanf("%d%d%d", &x[i], &y[i], &w);
      dist2origin[i] = abs(x[i]) + abs(y[i]);
      total_dist[i] = total_dist[i-1] + abs(x[i]-x[i-1]) + abs(y[i]-y[i-1]);
      total_weight[i] = total_weight[i-1] + w;
    }
    front = rear = 1;
    for (int i = 1; i <= n; i++) {
      while (front <= rear && total_weight[i] - total_weight[q[front]] > c) front++;
      d[i] = func(q[front]) + total_dist[i] + dist2origin[i];
      while (front <= rear && func(i) <= func(q[rear])) rear--;
      q[++rear] = i;
    }
    printf("%d\n", d[n]);
    if(T > 0) printf("\n");
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42835910/article/details/90113643