题目大意:有n个垃圾,第i个垃圾的坐标是(xi.yi),重量为wi。现有一个机器人,要按照编号从小到大的顺序捡起所有垃圾并放回垃圾桶,机器人的最大载重量为C,两点之间的距离为曼哈顿距离,求机器人行走的最短总路程
解题思路:用dp[i]表示捡到第i个垃圾回到原点所需要走的路程,dist[i]表示从原点走到第i点所需走的路程,len[i][j]表示从第i个点按顺序走到第j个点所需走的路程
由这几个,可以推出转换方程:dp[j] = dp[i] + len[i+1][j] + dist[i+1] + dist[j](前提是从第i+1个点按顺序到第j个点所捡的垃圾的总重量不大于C)
再假设total_dist[i]为从第1个垃圾按顺序捡到第i个垃圾所需要走的路程,则len[i+1][j] = total_dist[j] - total_dist[i+1],那么dp[j] = min(dp[i] - total_dist[i+1] + dist[i+1]) + dist[j] + total_dist[j]
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 100010
int len[maxn], dist[maxn], dp[maxn], x[maxn], y[maxn], weight[maxn], que[maxn];
int count(int cur) {
return dist[cur + 1] + dp[cur] - len[cur+1];
}
int main() {
int test, c, n, t, front, rear;
scanf("%d",&test);
while(test--) {
scanf("%d%d",&c,&n);
que[0] = x[0] = y[0] = dp[0] = dist[0] = len[0] = weight[0] = 0;
for(int i = 1; i <= n; i++) {
scanf("%d%d%d",&x[i],&y[i], &t);
dist[i] = abs(x[i]) + abs(y[i]);
weight[i] = weight[i-1] + t;
len[i] = len[i-1] + abs(x[i] -x[i-1]) + abs(y[i] - y[i-1]);
}
front = rear = 1;
for(int i = 1; i <= n; i++) {
while(front <= rear && weight[i] - weight[que[front]] > c)
front++;
dp[i] = count(que[front]) + len[i] + dist[i];
while(front <= rear && count(i) <= count(que[rear]))
rear--;
que[++rear] = i;
}
printf("%d\n",dp[n]);
if(test)
printf("\n");
}
return 0;
}