UVA1169 Robotruck

Dp+优化

首先我们考虑暴力怎么写?dp[i]表示选到i号辣鸡并将其放回的最优解,那么令dis[i]表示从1走到i的曼哈顿距离之和,from[i]表示从(0,0)走到i的曼哈顿距离,那么

\[dp[i]=min(dp[i],dp[j]+dis[i]-dis[j+1]+from[j+1]+from[i]); \]

\[0<=j<=i-1 \]

我们移项:
\(dp[i]=min(dp[i],dp[j]-dis[j+1]+from[j+1]+dis[i]+from[i]);\)

$ 0<=j<=i-1 $

显然,$$dp[j]-dis[j+1]+from[j+1]$$ 可以用线段树单调队列维护。

然后这道题就愉快的结束了(我用了线段树)

注意要换行!!!!

送大家一组样例,这组样例卡掉了一个CSDN的标程

in:

5
77
9
9 26 38
38 1 44
26 28 72
38 37 29
2 7 27
14 20 9
21 13 45
25 32 33
10 4 41
17
1
3 1 12
43
3
37 10 36
30 32 31
18 5 13
36
5
14 23 33
2 18 5
33 8 13
6 31 13
13 21 25
76
5
27 2 61
32 41 41
16 37 17
34 40 9
37 26 49

out

602

8

264

290

358

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
#define half (l+r)>>1
using namespace std;
const int maxn=100006;
inline int abs_(int x,int y)
{
    return x>y?x-y:y-x;
}
int x[maxn],y[maxn],w[maxn],from[maxn],cost[maxn],dp[maxn],n,sum[maxn];
struct hzw
{
    int lc,rc,mx;
}t[maxn*5];
int tot;
inline void build(int s,int l,int r)
{
    if(l==r)
    {
        t[s].mx=0x3f3f3f3f;
        return;
    }
    int mid=half;
    t[s].lc=++tot;
    build(tot,l,mid);
    t[s].rc=++tot;
    build(tot,mid+1,r);
}
inline void update(int s,int l,int r,int p,int x)
{
    if (l==p&&r==p)
    {
        t[s].mx=x;
        return;
    }
    int mid=half;
    if (p<=mid) update(t[s].lc,l,mid,p,x);
    else update(t[s].rc,mid+1,r,p,x);
    t[s].mx=min(t[t[s].lc].mx,t[t[s].rc].mx);
}
inline int query(int s,int l,int r,int cl,int cr)
{
    if (l==cl&&r==cr)
    {
        return t[s].mx;
    }
    int mid=half;
    if (cr<=mid) return query(t[s].lc,l,mid,cl,cr);
    else if (cl>mid) return query(t[s].rc,mid+1,r,cl,cr);
    else
    return min(query(t[s].lc,l,mid,cl,mid),
    	       query(t[s].rc,mid+1,r,mid+1,cr));
}
inline int search(int ll,int rr,int k)
{
    int l=ll,r=rr,ans=rr;
    while (l<=r)
    {
        int mid=half;
        if (cost[rr]-cost[mid-1]<=k)
        {
            r=mid-1;
            ans=min(ans,mid);
        }
        else l=mid+1;
    }
    return ans;
}
int main()
{
//	freopen("data.in","r",stdin);
//	freopen("baoli.out","w",stdout);
    int gg,maxx;
    cin>>gg;
    while (gg--)
    {
        memset(dp,0x3f,sizeof(dp));
        tot=1;
        cin>>maxx;
        scanf("%d",&n);
        build(1,0,n);
        for (int i=1;i<=n;++i)
        {
            scanf("%d%d%d",&x[i],&y[i],&w[i]);
            from[i]=x[i]+y[i];
            if (i>1) 
            sum[i]=sum[i-1]+abs_(x[i],x[i-1])+abs_(y[i],y[i-1]);
            cost[i]=cost[i-1]+w[i];
        }
    	dp[0]=0;
    	dp[1]=2*from[1];
		update(1,0,n,0,from[1]);
		update(1,0,n,1,from[2]-sum[2]+dp[1]);
		for (int i=2;i<=n;++i)
		{
			int wh=search(0,i,maxx);
			wh=max(0,wh-1);
			dp[i]=query(1,0,n,wh,i-1)+sum[i]+from[i];
			update(1,0,n,i,from[i+1]-sum[i+1]+dp[i]);
		}
		cout<<dp[n]<<endl;
		if (gg!=0)cout<<endl;
    }
    return 0;
}

收获:我们一定要先写出最裸的dp方程,再考虑优化

posted @ 2018-10-08 17:16  Splitor  阅读(121)  评论(0编辑  收藏  举报