题意:
求机器人将垃圾扔到垃圾桶的最短距离.
思路:
主要是基于一个等式:
dp[i] = dp[j] + dis[j + 1] +dist[i] - dist[j + 1] + dis[i] ;dp[i]表示扔垃圾的往返时间.
那么就是要求:min(dp[j] + dis[j + 1] -dist[j + 1]) +dist[i] + dis[i], 就引出dp[j]+dis[j+1]-dist[j+1]最小,而每个起点有基于算出的终点,所以保证终点的才能保证全局最小.
这里用到了单调队列,从后面删除,从前面读数.
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 100010;
int x[maxn],y[maxn],w[maxn];
int dist[maxn],weight[maxn],dis[maxn];
int q[maxn], dp[maxn];
int func(int i) {
return dp[i] - dist[i+1] + dis[i+1];
}
int main() {
int T;
int C, n, front, rear;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &C, &n);
for(int i=1; i<=n; i++) {
scanf("%d%d%d", &x[i],&y[i],&w[i]);
dist[i] = dist[i-1]+abs(x[i]-x[i-1]) + abs(y[i]-y[i-1]);
dis[i] = abs(x[i]) + abs(y[i]);
weight[i] = weight[i-1] + w[i];
}
front = rear = 1;
for(int i=1; i<=n; i++) {
while(front <= rear && weight[i]-weight[q[front]]>C)
front++;//找到最大承受的临界点
dp[i] = func(q[front]) + dis[i] + dist[i];
while(front<=rear && func(i)<=func(q[rear])) rear--;
q[++rear]=i;//在当前终点的基础上,若比已计算的终点小则替换,才能达到全局最优(路径不同)
}
printf("%d\n", dp[n]);
if(T) printf("\n");
}
return 0;
}