UVA 1169 【单调队列优化dp】

来源:互联网 发布:淘宝手机专享价 编辑:程序博客网 时间:2024/06/06 12:25

题意:给出机器人的最大负重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)|1using 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;}


0 0
原创粉丝点击