【暑假】[深入动态规划]UVAlive 3983 Robotruck

时间:2021-02-13 11:08:06

 UVAlive 3983 Robotruck

 

题目:

 

 
Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu

 

 Status

Description

 

Problem C - Robotruck

Background

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.

Problem

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

Input

Input consists of multiple test cases the first line of the input contains the number of test cases. There is a blank line before each dataset. The input for each dataset consists of a line containing one positive integer C, not greater then 100, indicating the maximum capacity of the robot, a line containing one positive integer N, not greater than 100,000, which is the number of packages to be loaded from the conveyer. Next, there are N lines containing, for each package, two non-negative integers to indicate its delivery location in the grid, and a positive integer to indicate its weight. The weight of the packages is always smaller than the robot�s maximum load capacity. The order of the input is the order of appearance in the conveyer.

Output

One line containing one integer representing the minimum number of moves the robot must travel to deliver all the packages. Print a blank line between datasets.

Sample Input

1

 

10

4

1 2 3

1 0 3

3 1 4

3 1 4

Sample Output

14

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

思路:

  设d[i]为将前i个垃圾收完并放进垃圾桶的最小距离。同时定义total_dist[i]为从0点依次走过前i个垃圾到i的曼哈顿距离和,定义dist2origin[i]为i到0点的曼哈顿距离。

  转移方程:

     d[i]=min{d[j]-total_dist(j+1)+dist2origin(j+1)  // j 满足w(j+1,i)<=c } +total_dist[i]+dist2origin[i]   //代表一次将j+1..i的垃圾收回放到0点

单调队列优化:

    设func(j)=d[j]-total_dist(j+1)+dist2origin(j+1) 则转移方程为:d[i]=min{func(j)  // j 满足w(j+1,i)<=c } + ...

    用单调队列维护一个满足w(q[front]+1,i)<=c的滑动窗口,单调队列中的值按照func的递增序排列。每次考虑一个新的i 都要适当移动窗口,使得满足单调队列的性质。维护的单调队列可以在O(1)的时间内返回min{func(j)  // j 满足w(j+1,i)<=c}

   具体操作如下:

1         int q[maxn];  //单调队列 
2         front=rear=1;
3         for(int i=0;i<=n;i++) {    
4             while(front<=rear && total_w[i]-total_w[q[front]]>c) front++;  //维护队列中w(j+1,i)<=c 
5             d[i]=func(q[front]) + total_dist[i] + dist2origin[i];         //func(q[front])是队列中的最小值 
6             while(front<=rear && func(i)<=func(q[rear])) rear--;          //维护单调队列中的单调递增序  
7             q[++rear]=i;
8         }

 

 

完整代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int maxn = 100000 + 10;
 6 
 7 int x[maxn],y[maxn];
 8 int total_dist[maxn],dist2origin[maxn],total_w[maxn];
 9 int d[maxn];
10 
11 inline int func(int j) {
12     return d[j]-total_dist[j+1]+dist2origin[j+1];
13 }
14 
15 int main() {
16     int T,n,c,w,front,rear;
17     cin>>T;
18     while(T--) {
19         cin>>c>>n;
20         total_w[0]=total_dist[0]=x[0]=y[0]=0;
21         for(int i=1;i<=n;i++) {  
22             cin>>x[i]>>y[i]>>w;
23             total_w[i]=total_w[i-1]+w;
24             total_dist[i]=total_dist[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
25             dist2origin[i]=abs(x[i])+abs(y[i]);
26         }
27         
28         int q[maxn];  
29         front=rear=1;
30         for(int i=0;i<=n;i++) {    
31             while(front<=rear && total_w[i]-total_w[q[front]]>c) front++;  
32             d[i]=func(q[front]) + total_dist[i] + dist2origin[i];         
33             while(front<=rear && func(i)<=func(q[rear])) rear--;          
34             q[++rear]=i;
35         }
36         
37         cout<<d[n]<<endl;
38         if(T) cout<<endl;
39     }
40 }