zoj 3469 Food Delivery (区间dp)

没想到还会回来写博客,算是回忆下把,来一道区间dp基础题。

题意:一个送外卖的从某个出发点送外卖,但是每个顾客地点都有一个不满意值,会随着时间每秒增加b[i],每个顾客地点都有一个距离,可以人为是在x轴上的坐标。现在问如何送外卖使得不满意度最小。

题解:好像做过,不过这次换了一个更优美的姿势过,记忆优化写起来会比较好写,而且姿势优美。

dp[i][j][pos]表示[l,r]区间的顾客都送完了现在位于pos位置,pos==0表示在左边,pos==1表示在右边。

每次可以选择往区间左端或这右端走。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1005;
ll dp[maxn][maxn][2];
int vis[maxn][maxn][2];
ll sum[maxn];
struct Node{
	int x,b;
}a[maxn];
int n, X, V;

void cmin(ll& a,ll b){
	if(b < a) a = b;
}

ll dfs(int l,int r,int pos){
	if(l==1 && r==n) return 0;
	if(vis[l][r][pos]) return dp[l][r][pos];
	ll res=INF;
	int cost = sum[n]-sum[r] + sum[l-1] - sum[0];
	if(pos==0){
		if(l-1>=1)
			cmin(res, dfs(l-1,r,0) + (a[l].x-a[l-1].x)*cost);
		if(r+1<=n)
			cmin(res, dfs(l,r+1,1) + (a[r+1].x-a[l].x)*cost);
	}
	else{
		if(l-1>=1)
			cmin(res, dfs(l-1,r,0) + (a[r].x-a[l-1].x)*cost);
		if(r+1<=n)
			cmin(res, dfs(l,r+1,1) + (a[r+1].x-a[r].x)*cost);
	}
	vis[l][r][pos]=1;
	return dp[l][r][pos]=res;
}

bool cmp(const Node& n1, const Node& n2){
	return n1.x<n2.x;
}

int main(){
	//freopen("read.txt","r",stdin);
	int pos;
	while(scanf("%d%d%d",&n,&V,&X)!=EOF){
		for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].b);
		a[++n].x=X;
		a[n].b=-1;
		sort(a+1,a+1+n,cmp);
		for(int i=1;i<=n;i++){
			if(a[i].x==X && a[i].b==-1)
				pos=i;
			sum[i]=sum[i-1]+a[i].b;
		}
		memset(vis,0,sizeof vis);
		memset(dp,-1,sizeof dp);
		printf("%lld\n",min(dfs(pos,pos,0),dfs(pos,pos,1))*V);
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值