UVA3983 Robotruck 题解

题目描述

有n个垃圾,第i个垃圾的坐标为(xi,yi),重量为wi。有一个机器人,要按照编号从小到大的顺序捡起所有垃圾并扔进垃圾桶(垃圾桶在原点(0,0))。机器人可以捡起几个垃圾以后一起扔掉,但任何时候其手中的垃圾总重量不能超过最大载重C。两点间的行走距离为曼哈顿距离(即横坐标之差的绝对值加上纵坐标之差的绝对值)。求出机器人行走的最短总路程(一开始,机器人在(0,0)处)。

输入格式:

输入的第一行为数据组数T(1<=T<=15),每组数据的第一行为最大承重C(1<=C<=100);第二行为正整数n(1<=n<=100000),即垃圾的数量;一下n行每行为三个非负整数x,y,w,即坐标和重量(重量保证不超过C)。

输出格式:

对于每组数据,输出总路径的总长度。

又是一道单调队列优化的DP。按照这种题目的一般解决过程,我们应当先写出暴力DP的状态转移方程,然后再针对其方程的特点选择合适的优化方式进行优化。

先前缀和预处理一下吧,有什么用往下看就知道了。我们用s[i]表示1--i个垃圾的总重量,step[i]表示1--i的总路程长度(不回垃圾桶处)。

然后,我们设f[i]表示捡了第i个垃圾并回到垃圾桶的最短的总路程的长度,那么对于每一个i,我们枚举j(1<=j<=i&&s[i]-s[j-1]<=C),意为“捡完1--j-1的全部垃圾回到垃圾桶后,再出发一次性捡完j--i的所有垃圾”,其中s[i]-s[j-1]<=C是因为机器人所捡垃圾重量不能超过他的最大载重。

那么状态转移方程是什么呢?显然,捡完1--j-1的全部垃圾并回到垃圾桶处后,机器人必须先得到达j点,然后一步一步走到i点,最后再走回原点,分为三段,所以状态转移方程就显而易见了:

\[ f[i]=min(f[j-1]+x[j]+y[j]+step[i]-step[j]+x[i]+y[i])(1<=j<=i&&s[i]-s[j-1]<=C) \]

由于i在当下是固定的,所以(step[i]+x[i]+y[i])的值也是固定的,那么想要所取的值最小,就是要(f[j-1]+x[j]+y[j]-step[j])的值最小。对于维护最小值的事,当然要请来单调队列啦,我们设x=f[j-1]+x[j]+y[j]-step[j],将x与单调队列的队尾元素的值进行比较,取较小的那一个。同时,队首j也要及时判断是否满足(s[i]-s[j-1]<=C),不满足即出队。

代码如下:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int T,C,n,x[100001],y[100001],w[100001];
    long long s[100001],step[100001],f[100001],q[100001],p[100001],head,tail,k;
    int main()
    {
        scanf("%d",&T);
        for(register int i=1;i<=T;i+=1)
        {
            scanf("%d",&C);
            scanf("%d",&n);
            for(register int i=1;i<=n;i+=1)
            {
                scanf("%d%d%d",&x[i],&y[i],&w[i]);
                s[i]=s[i-1]+w[i];
                step[i]=step[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
            }
            head=1;tail=0;
            for(register int i=1;i<=n;i+=1)
            {
                k=f[i-1]+x[i]+y[i]-step[i];
                while(head<=tail&&p[tail]>=k)tail--;
                q[++tail]=i;
                p[tail]=k;
                while(head<=tail&&s[i]-s[q[head]-1]>C)head++;
                f[i]=p[head]+step[i]+x[i]+y[i];
            }
            printf("%lld\n",f[n]);
        }
        return 0;
}

猜你喜欢

转载自www.cnblogs.com/ForwardFuture/p/9022059.html