UVA 1169uvalive 3983 Robotruck 单调队列优化DP

题意:有n个垃圾,坐标为(xi,yi)重量为wi。有一个机器人,要按照编号从小到大的顺序捡起所有垃圾并扔进垃圾桶(坐标(0,0))。机器人可以捡起几个垃圾以后一起扔掉,但任何时候其手中的垃圾总重量不能超过C.两点间的行走距离为曼哈顿距离。求出机器人行走的最短距离。

设dp[i]为机器人清理完前i个垃圾所走的最短路程,则,

dp[i]=min{dp[j]+dist(0,j+1)+dist(j+1,j+2)+dist(j+2,j+3)...+dist(i-1,i) + dist(i,0) | j<i,sumw[j+1...i]<=C};0为原点

用totald[i]表示dist(O,1)+dist(1,2)+..+dist(i-1,i)

则dist(j+1,j+2)+...+dist(i-1,i)=totald[i]-totald[j+1];

dp[i]=min{dp[j]+dist(0,j+1)-totald[j+1] | j<i,sumw[j+1...i]<=C }+totald[i]+dist(0,i);

可用单调队列优化

const int maxn=100100;
int dp[maxn],totald[maxn],totalw[maxn];
int x[maxn],y[maxn],w[maxn];
int dist(int a,int b)
{
    return abs(x[a]-x[b])+abs(y[a]-y[b]);
}
int f(int id)
{
    return dp[id]+dist(0,id+1)-totald[id+1];
}
int q[maxn];
int work(int n,int c)
{
    int front=1,rear=2;
    dp[0]=0;
    q[1]=0;
    for(int i=1;i<=n;i++)
    {
        while(rear>front&&totalw[i]-totalw[q[front]]>c)front++;
        dp[i]=f(q[front])+dist(i,0)+totald[i];
        while(rear>front&&f(i)<f(q[rear-1]))rear--;
        q[rear++]=i;
    }
    return dp[n];
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int ca=1;ca<=t;ca++)
    {
        int n,c;
        scanf("%d%d",&c,&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&x[i],&y[i],&w[i]);
            totald[i]=totald[i-1]+dist(i-1,i);
            totalw[i]=totalw[i-1]+w[i];
        }
        int num=work(n,c);
        printf("%d
",num);
        if(ca!=t)printf("
");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/BMan/p/3249970.html