LA 3983 Robotruck(DP)

题意:有n个垃圾且有各自的重量,一个机器人按标号从小到大开始捡垃圾,且手中的垃圾重量不能超过C,问机器人怎样捡才能使他的行走路程最短。


思路:dp,设dp[i] : 拾取完前i个垃圾的最短路程,则有dp[i + k] = min { dp[i] + dis[i + 1] + dis[i + k] + tal[i + k] - tal[i + 1] },其中dis[i]为第i个垃圾距离源点的曼哈顿距离,tal[i] 为从0开始拾取垃圾一直拾取到第i个垃圾时的曼哈顿距离。显然这里有一个区间的滚动,很容易想到单调队列优化。


#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
const int INF = 1e9;
const int maxn = 1e5 + 10;
using namespace std;

int T, C, n;
int x[maxn], y[maxn];
int dis[maxn], tal[maxn];
int dp[maxn], q[maxn];
int st[maxn], w[maxn];

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &C, &n);
        tal[0] = x[0] = y[0] = 0;
        dp[0] = 0;
        memset(w, 0, sizeof w);
        memset(tal, 0, sizeof tal);
        memset(dis, 0, sizeof dis);
        for(int i = 1; i <= n; i++) {
            dp[i] = INF; st[i] = i;
            scanf("%d %d %d", &x[i], &y[i], &w[i]);
            dis[i] = x[i] + y[i];
            tal[i] = tal[i - 1] + abs(x[i] - x[i - 1]) + abs(y[i] - y[i - 1]);
        }
        int di = 0, j = 0;
        int real = 0, tail = 0;
        q[tail++] = 0;
        for(int i = 0; i <= n; i++) {
            di -= w[i];
            if(j) { j--; di -= w[j]; }
            while(j <= n && di <= C) {
                di += w[j];
                if(di <= C) st[j] = min(i, st[j]);
                j++;
            }
            while(real < tail && q[real] < st[i]) real++;
            int jj = q[real];
            dp[i] = dp[jj] + tal[i] + dis[i];
            dp[i] += dis[i + 1] - tal[i + 1];
            while(real < tail && dp[q[tail - 1]] >= dp[i]) tail--;
            q[tail++] = i;
        }
        printf("%d\n", dp[n]);
        if(T) printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值