UVA 1169\uvalive 3983 Robotruck 单调队列优化DP
题意:有n个垃圾,坐标为(xi,yi)重量为wi。有一个机器人,要按照编号从小到大的顺序捡起所有垃圾并扔进垃圾桶(坐标(0,0))。机器人可以捡起几个垃圾以后一起扔掉,但任何时候其手中的垃圾总重量不能超过C.两点间的行走距离为曼哈顿距离。求出机器人行走的最短距离。
设dp[i]为机器人清理完前i个垃圾所走的最短路程,则,
dp[i]=min{dp[j]+dist(0,j+1)+dist(j+1,j+2)+dist(j+2,j+3)...+dist(i-1,i) + dist(i,0) | j<i,sumw[j+1...i]<=C};0为原点
用totald[i]表示dist(O,1)+dist(1,2)+..+dist(i-1,i)
则dist(j+1,j+2)+...+dist(i-1,i)=totald[i]-totald[j+1];
dp[i]=min{dp[j]+dist(0,j+1)-totald[j+1] | j<i,sumw[j+1...i]<=C }+totald[i]+dist(0,i);
可用单调队列优化
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
const int maxn=100100; int dp[maxn],totald[maxn],totalw[maxn]; int x[maxn],y[maxn],w[maxn]; int dist(int a,int b) { return abs(x[a]-x[b])+abs(y[a]-y[b]); } int f(int id) { return dp[id]+dist(0,id+1)-totald[id+1]; } int q[maxn]; int work(int n,int c) { int front=1,rear=2; dp[0]=0; q[1]=0; for(int i=1;i<=n;i++) { while(rear>front&&totalw[i]-totalw[q[front]]>c)front++; dp[i]=f(q[front])+dist(i,0)+totald[i]; while(rear>front&&f(i)<f(q[rear-1]))rear--; q[rear++]=i; } return dp[n]; } int main() { int t; scanf("%d",&t); for(int ca=1;ca<=t;ca++) { int n,c; scanf("%d%d",&c,&n); for(int i=1;i<=n;i++) { scanf("%d%d%d",&x[i],&y[i],&w[i]); totald[i]=totald[i-1]+dist(i-1,i); totalw[i]=totalw[i-1]+w[i]; } int num=work(n,c); printf("%d\n",num); if(ca!=t)printf("\n"); } return 0; }