zoj 3031 Robotruck(dp + 单调队列)
题意:有n个垃圾,机器人要按照编号从小到大捡但手中的垃圾不得超过C,求出机器人行走的最短总路程。
做法:设dp[i]为捡第i个垃圾的最短距离,dist[i]为按顺序的总长,dis_ori[i]为i到原点的距离。
不难得出:dp[i] = min{dp[j] + dis_ori[j+1] + distance[j+1,i] + dis_ori[i] } ; w(j+1,i)<=C
= min{dp[j] + dis_ori[j+1] - dist[j+1]} + dist[i] + dis_ori[i] ; w(j+1,i)<=C
用单调队列可以解决min的值,复杂度O(n) , 注意long long。
单调队列(窗口滑动技术):
对于每一个状态f(x)来说,计算过程分为以下几步:
1、 队首元素出队,直到队首元素在给定的范围中。
2、 此时,队首元素就是状态f(x)的最优决策。
3、 计算g(x),并将其插入到单调队列的尾部,同时维持队列的单调性(不断地出队,直到队列单调为止)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 Author:Zhaofa Fang 3 Lang:C++ 4 */ 5 #include <cstdio> 6 #include <cstdlib> 7 #include <sstream> 8 #include <iostream> 9 #include <cmath> 10 #include <cstring> 11 #include <algorithm> 12 #include <string> 13 #include <utility> 14 #include <vector> 15 #include <queue> 16 #include <stack> 17 #include <map> 18 #include <set> 19 using namespace std; 20 21 typedef long long ll; 22 #define DEBUG(X) cout<< #X << ':' << X << endl 23 #define REP(i,n) for(int i=0;i < (n);i++) 24 #define FOR(i,s,t) for(int i = (s);i <= (t);i++) 25 #define PII pair<int,int> 26 #define PB push_back 27 #define MP make_pair 28 #define ft first 29 #define sd second 30 #define lowbit(X) (X&(-X)) 31 #define INF (1<<30) 32 33 34 const int maxn = 1e5+10; 35 ll dp[maxn],w[maxn],dist[maxn],dis_ori[maxn]; 36 int X[maxn],Y[maxn]; 37 int q[maxn]; 38 ll fun(int j) 39 { 40 return dp[j] + dis_ori[j+1] - dist[j+1]; 41 } 42 inline int Abs(int k) 43 { 44 return k>0?k:(-k); 45 } 46 int main() 47 { 48 //freopen("in","r",stdin); 49 int T; 50 scanf("%d",&T); 51 FOR(cas,1,T) 52 { 53 int C,n; 54 scanf("%d%d",&C,&n); 55 dp[0] = dist[0] = dis_ori[0] = w[0] = X[0] = Y[0] = 0; 56 FOR(i,1,n) 57 { 58 scanf("%d%d%lld",&X[i],&Y[i],&w[i]); 59 w[i] += w[i-1]; 60 dist[i] = dist[i-1] + Abs(X[i]-X[i-1]) + Abs(Y[i]-Y[i-1]); 61 dis_ori[i] = Abs(X[i]) + Abs(Y[i]); 62 } 63 int front=0,rear=0; 64 q[rear++] = 0; 65 FOR(i,1,n) 66 { 67 68 while(front < rear && w[i] - w[q[front]] > C)front++; 69 dp[i] = fun(q[front]) + dist[i] + dis_ori[i]; 70 while(front < rear && fun(q[rear-1]) >= fun(i))rear--; 71 q[rear++] = i; 72 } 73 printf("%lld\n",dp[n]); 74 } 75 return 0; 76 }
by Farmer