uva1169 - Robotruck

题意:
n个垃圾,有其坐标(x,y)即重量w,一机器人最多承受重量C,要按其编号依次去捡垃圾(它只能上下左右走)然后倒垃圾,垃圾桶在原点(0,0),求倒完所有垃圾需走的最小距离。
思路:

直接dp的话复杂度O(100000*100)过大,因而用单调队列来优化。
dp[i]表示倒前i个垃圾的最小距离,sumd[i]表示前i个垃圾的曼哈顿距离,sumw[i]表示前i个垃圾的重量和,p[i].d表示i到原点的曼哈顿距离。
dp[i]=dp[j]+sumd[i] - sumd[j + 1] + p[j + 1].d+p[i].d.

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;

const int N = 100005;
int w, n, sumw[N], sumd[N], dp[N];

struct point {
    int x, y, w, d;
}p[N], zero;

int dis(point a,point b) {
    return abs(a.x - b.x) + abs(a.y - b.y);
}
int func(int j) {
    return dp[j] - sumd[j + 1] + p[j + 1].d;
}
int solve(){
    deque<int> Q;//用单调队列控制滑动窗口func的最小值
    Q.push_front(0); //dp[i]=min{func(j)|w(j+1,i)<w)+sumd[i]+p[i].d
    for (int i = 1; i <= n; i++) {
        while (!Q.empty() && sumw[i] - sumw[Q.front()] > w)  {
            Q.pop_front();
        }
        dp[i] = func(Q.front()) + sumd[i] + p[i].d;
        while (!Q.empty()&&func(i)<=func(Q.back())) {
            Q.pop_back();
        }
        Q.push_back(i);
    }
    return dp[n];
}
int main() {
    int cas;
    scanf("%d",&cas);
    while (cas--) {
        memset(p, 0, sizeof(p));
        memset(sumw, 0, sizeof(sumw));
        memset(sumd, 0, sizeof(sumd));
        scanf("%d%d", &w, &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].w);
            sumw[i] = sumw[i - 1] + p[i].w;
            sumd[i] = sumd[i - 1] + dis(p[i], p[i - 1]);
            p[i].d = dis(p[i], zero);
        }
        printf("%d\n", solve());
        if (cas)
            printf("\n");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值