UVA 1169 【单调队列优化dp】

题意:给出机器人的最大负重c,和n个垃圾,接下来n行代表垃圾的坐标和重量w,

一开始机器人在原点,机器人只能走横竖,机器人可以拿多个垃圾,只要不超过最大负重,然后放回垃圾桶,垃圾桶在原点,
问机器人将所有垃圾放到垃圾桶最少需要走的距离。

分析:定义dp[i]表示,前i个垃圾放回垃圾桶的最短距离。

转移方程为:dp[i]=min(dp[j]+dis0[j+1]+sumdis[i]-sumdis[j+1]+dis0[i]).

换个写法dp[i]=min(dp[j]+dis0[j+1]-sumdis[j+1])+dis0[i]+sumdis[i]。

j+1到i的w和要小于c,可以知道上面式子前面取min的部分是个滑动窗格。

我们可以用单调队列维护这个窗格,每次对首就是最小的j。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 100010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int dp[Mn],dis[Mn];
int q[Mn];
int x[Mn],y[Mn],w,wtot[Mn];
int get(int j) {
    return dp[j]-dis[j+1]+abs(x[j+1])+abs(y[j+1]);
}
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int c,n;
        scanf("%d%d",&c,&n);
        for(int i=1;i<=n;i++) {
            scanf("%d%d%d",&x[i],&y[i],&w);
            dis[i]=dis[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
            wtot[i]=wtot[i-1]+w;
        }
        int sum=0,fr=1,re=1;
        CLR(dp,0);
        CLR(q,0);
        for(int i=1;i<=n;i++) {
            while(fr<=re&&wtot[i]-wtot[q[fr]]>c) fr++;
            dp[i]=get(q[fr])+dis[i]+abs(x[i])+abs(y[i]);
            while(fr<=re&&get(i)<=get(q[re])) re--;
            q[++re]=i;
        }
        printf("%d\n",dp[n]);
        if(t>0) printf("\n");
    }
    return 0;
}


你可能感兴趣的:(UVA 1169 【单调队列优化dp】)