*UVA 1169Robotruck ACM解题报告(dp单调队列优化)

来源:互联网 发布:淘宝跨境电商平台 编辑:程序博客网 时间:2024/05/17 22:09

本渣也是在努力地刷着大白,虽然基本每题都做不出,但是每题都能理解,然后自己实现,再写个报告,希望这样的方法能有用。

这题给出了n个垃圾的坐标和重量,然后机器人的最大承重是c,捡垃圾的时候必须按照垃圾的顺序捡。

这题一上来我就想到背包,要么捡,要么回去,这样的方法其实是可以的,只是复杂度比较高,如果数据比较坑,可能会过不了。但是这题可以。

大白上介绍的方法是一种非常巧妙的单调队列优化。

origin数组是原点到点i的曼哈顿距离,total数组是沿着一个个垃圾的顺序,到垃圾i的距离。

d[i]表示收集了垃圾i之后回到原点所需要的最短距离,所以答案就是d[n],d[i]=d[j]+origin[j+1]+(total[i]-total[j+1])+origin[i];满足第j+1个垃圾到第i个垃圾的重量和小于等于c

状态转移方程:d[i]=min(d[j]+origin[j+1]-total[j+1])+origin[i]+total[i]。

单调队列优化就是维护一段区间,这段区间内从头到尾的垃圾重量都小于等于c,并且距离单调递增,考察一个新的垃圾i,如果这个垃圾到队列首元素的重量和大于c,那么队首元素就要舍弃,因为大于c之后就不能从队首元素开始运,弹出第一个元素,继续考察队首元素,直到队列的重量和小于等于c。d[i]=从此时的队首元素开始到i的距离(因为这是单调队列,队列里的其他元素d[k]都大于d[front],所以垃圾i必定是从队首元素开始运的)

然后如果当前计算出来的d[i]小于等于队列最后的元素,就要舍弃比d[i]大或者相等的元素,如果比d[i]大,那么运后面的垃圾,显然从i开始比从前面几个垃圾开始更优。

如果相等,那么从i开始不会比从前面几个开始更坏,因为i到后面某个元素的重量和更小,如果在i前面的垃圾,d的值和i的一样,也许那个垃圾到后面某个垃圾的重量和会超出c,就得不到最优解了。

所以就是维护区间的重量和小于等于c,如果不满足,头指针++,如果得到的解比队列最后的元素更小,那么就插到比它小的元素后面,并且比它大的舍弃。

#include<iostream>#include<cstdio>#include<cctype>#include<cstdlib>#include<cmath>#include<algorithm>#include<cstring>#include<string>#include<vector>#include<queue>#include<map>#include<set>#include<sstream>#include<stack>using namespace std;#define MAX 100005typedef long long LL;const double pi=3.141592653589793;const int INF=1e9;const double inf=1e20;const double eps=1e-6;int x[MAX],y[MAX];int total[MAX];//记录按顺序从1-i走的距离int origin[MAX];//记录从原点走到i的距离int w[MAX];//记录前i个垃圾的重量int c,n;int d[MAX];//记录收集了第i个垃圾后运回去后所走的最短距离int q[MAX];//滑动窗口单调队列,优化队列int func(int i){return d[i]+origin[i+1]-total[i+1];}int main(){int t,p;cin>>t;while(t--){scanf("%d %d",&c,&n);x[0]=y[0]=w[0]=total[0]=origin[0]=0;for(int i=1;i<=n;i++){scanf("%d%d%d",&x[i],&y[i],&p);w[i]=w[i-1]+p;total[i]=total[i-1]+fabs(x[i]-x[i-1])+fabs(y[i]-y[i-1]);origin[i]=fabs(x[i])+fabs(y[i]);}int front=0,last=0;q[front]=0;for(int i=1;i<=n;i++){while(front<=last&&w[i]-w[q[front]]>c) front++;d[i]=func(q[front])+total[i]+origin[i];while(front<=last&&func(i)<=func(q[last])) last--;q[++last]=i;}printf("%d\n",d[n]);if(t>0) printf("\n");}    return 0;}

0 0
原创粉丝点击