题意:
一个机器人从(0,0)开始按照序号从小到大依次拣起n个坐标点上的垃圾(重量为ci),并回到原点。但是任何时候手上垃圾都不能超过重量C。任意两点距离为曼哈顿距离。求机器人行走的最短路程。
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 greaterthan 100,000, which is the number of packages to be loaded from the conveyer. Next, there are N linescontaining, for each package, two non-negative integers to indicate its delivery location in the grid, anda positive integer to indicate its weight. The weight of the packages is always smaller than the robotsmaximum load capacity. The order of the input is the order of appearance in the conveyer.
Output
For each test case, print one line containing one integer representing the minimum number of movesthe 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
分析:
f[i]表示前i个垃圾需要的最大距离;
dist[i]是捡起前i个垃圾的总距离;
sumw[i]是重量的前缀和;
origin[i]是i号垃圾到原点的距离;
对于f[i]讨论这一趟捡起从j+1到i的垃圾,不难得到方程:
f[i]=min{f[j]+dist[i]-dist[j+1]+origin[i]+origin[j+1]} (sumw[i]-sum[j]<=maxw)
动规时间复杂度为O(n^2),maxn=100000,显然会TLE。
在对方程进行研究不难得到:
f[i]=dist[i]+origin[i]+ min{f[j]-dist[j+1]+origin[j+1]} (sumw[i]-sum[j]<=maxw)
令value(j)=f[j]-dist[j+1]+origin[j+1];
则min{value[j]}可以通过单调队列预处理得到,滑动窗口模型,窗口限制: (sumw[i]-sum[j]<=maxw)
代码如下:
#include<cstdio> #include<iostream> #include<cstdlib> using namespace std; const int maxn=100000+5; int x[maxn],y[maxn]; int dist[maxn],origin[maxn],sumw[maxn]; int n,f[maxn],q[maxn],maxw; inline void _read(int &x){ char ch=getchar(); bool mark=false; for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true; for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0'; if(mark)x=-x; } void input(){ int i,w; _read(maxw);_read(n); for(int i=1;i<=n;i++){ _read(x[i]);_read(y[i]);_read(w); //前缀和计算 sumw[i]=sumw[i-1]+w; origin[i]=x[i]+y[i]; dist[i]=dist[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]); } } int value(int x){ return f[x]-dist[x+1]+origin[x+1]; } void solve(){ int i,front,rear; f[0]=dist[0]=sumw[0]=0; front=0;rear=1; //注意初值 for(i=1;i<=n;i++){ while(front!=rear&&sumw[i]-sumw[q[front]]>maxw)front++; f[i]=origin[i]+dist[i]+value(q[front]); while(front!=rear&&value(q[rear-1])>=value(i))rear--; //维持单调递增 q[rear++]=i; } printf("%d\n",f[n]); } int main(){ int t; _read(t); while(t--){ input(); solve(); if(t>0)putchar('\n'); //注意格式要求 } }