题意: 给n个垃圾的(n<100000)坐标x,y,每个垃圾一个重量,给定一个机器人,可以承重C,机器人从原点出发,要求按照顺序依次将1-n的垃圾回收到原点,求最小路程?
题解: 动态规划思路,di = min(dj+H(j+1)+Sumi-Sumj+1+Hi), di表示将前i个垃圾回收到原点的最短路程,Sum[i]表示从垃圾1依次走到垃圾i的路程,Hi表示i号垃圾到原点的曼哈顿距离(即x与y坐标差的绝对值和),遍历的时候维护下dj+H[j+1]-Sum[j+1]的最小值即可,不维护的话时间复杂度是n^2,用优先队列维护后应该是线性时间复杂度,网上的题解看似乎也可以用单调队列
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define MAXN 100010
using namespace std;
int C,n;
int x[MAXN],y[MAXN],c[MAXN];
int H[MAXN],HSum[MAXN],CSum[MAXN];
int dp[MAXN];
struct Node {
int value,index;
bool operator < (const Node &n) const {
return value > n.value;
}
};
priority_queue<Node> q;
void Init() {
memset(H,0,sizeof(H));
memset(HSum,0,sizeof(HSum));
memset(dp,0,sizeof(dp));
while(!q.empty()) q.pop();
}
// di = dj+H(j+1)+Sumi-Sumj+1+Hi
int main() {
int T;
scanf("%d",&T);
while(T--) {
Init();
scanf("%d%d",&C,&n);
for(int i = 1;i <= n;i++) {
scanf("%d%d%d",&x[i],&y[i],&c[i]);
H[i] = abs(x[i]) + abs(y[i]);
HSum[i] = (i==1?H[1]:HSum[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]));
CSum[i] = (i==1?c[1]:c[i]+CSum[i-1]);
}
for(int i = 1;i <= n;i++) {
int t = dp[i-1]+H[i]-HSum[i];
q.push((Node){t,i-1});
while(!q.empty()) {
Node node = q.top();
int j = node.index;
if(CSum[i] - CSum[j] > C) {
q.pop();
continue;
}
dp[i] = node.value + HSum[i] + H[i];
break;
}
}
printf("%d\n",dp[n]);
if(T) printf("\n");
}
return 0;
}