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),并将其插入到单调队列的尾部,同时维持队列的单调性(不断地出队,直到队列单调为止)。

View Code
 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 }

你可能感兴趣的:(robot)