zzuli 2172 队列优化dp
2172: GJJ的日常之购物
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 9 Solved: 8
SubmitStatusWeb Board
Description
一天,GJJ去购物,来到商场门口,GJJ计划要买n个商品,第i个商品的坐标为(xi,yi),重量是wi。
GJJ比较任性,想按照商品编号从小到大的顺序将所有的商品的搬到车里(车在(0,0)的位置);
GJJ可以几个商品一起搬,但在任何时候GJJ手中的商品重量不能超过最大载重C。
商场的过道只有横着的和竖着的。求GJJ行走的最短距离(GJJ的起始位置为(0,0))。
Input
第一行输入一个T(T<=10),表示T组数据。
每组数据第一行为最大载重C(1<=C<=100),商品个数n(n<=100000);
接下来n行,每行为xi,yi,wi,(0<=xi,yi<=100,wi<=C)既商品的坐标和重量
Output
对于每组数据,输出总路径的最短长度。
Sample Input
2
10 4
1 2 3
1 0 3
3 1 4
3 1 4
5 1
1 1 2
Sample Output
14
4
推了1h方程可惜是错误的= =。
可以理解为取第i件物品时是取了前j件物品(j<i)放回车后,再次取i之前j之后的物品一次性取到i然后返回(如果可以的话).
设f(i)表示为 将前i件物品放到车上的最短距离 d1[i]表示0->1->2......->i点所有距离之和 d2[i]表示0->i的距离
那么我们有 f[i]=MIN{ f[j]+d2[j+1]+d1[i]-d1[j+1]+d2[i] | j<i&&j+1至i所有物品重量<=C }
f[i]=MIN{ f[j]+d2[j+1]-d1[j+1] }+d1[i]+d2[i] ;
对于MIN里的显然我们可以维护一个最小值,优先队列即可完成,每计算出一个f[i]时就push进去一个 f[i]+d2[i+1]-d1[j-1],
每次取队首时要判断是否满足重量条件,如果不满足直接pop,因为后面的更不会满足,这个节点已经没用。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 #define inf 0x3f3f3f3f 5 int d1[100005],d2[100005],f[100005]; 6 int x[100005],y[100005],w[100005]; 7 struct node 8 { 9 int u,w; 10 bool operator<(const node &tmp)const{ 11 return w>tmp.w; 12 } 13 }; 14 priority_queue<node>Q; 15 int main() 16 { 17 // freopen("in.txt","r",stdin); 18 int T,C,N,i,j,k; 19 cin>>T; 20 while(T--){ 21 while(!Q.empty()) Q.pop(); 22 cin>>C>>N; 23 for(i=1;i<=N;++i) 24 { 25 scanf("%d%d%d",&x[i],&y[i],&w[i]); 26 w[i]+=w[i-1]; 27 d1[i]=d1[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]); 28 d2[i]=x[i]+y[i]; 29 } 30 f[1]=d2[1]*2; 31 Q.push(node{0,0}); 32 Q.push(node{1,f[1]+d2[2]-d1[2]}); 33 for(i=2;i<=N;++i) 34 { 35 node tmp=Q.top(); 36 while(!Q.empty()&&w[i]-w[tmp.u]>C){ 37 Q.pop(); 38 tmp=Q.top(); 39 } 40 f[i]=tmp.w+d2[i]+d1[i]; 41 Q.push(node{i,f[i]-d1[i+1]+d2[i+1]}); 42 } 43 cout<<f[N]<<endl; 44 } 45 return 0; 46 } 47 //注释freopen语句!!!