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方程,再考虑优化