UVA 1169 DP+单调队列优化 Robotruck 捡垃圾的机器人

本文探讨了一种利用动态规划解决机器人在限定载重条件下收集垃圾并返回起点的问题,通过优化算法实现时间复杂度的有效降低。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

一个机器人从(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');  //注意格式要求 
	} 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值