Food Delivery ZOJ - 3469(区间dp)
Posted zhi-71
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Food Delivery ZOJ - 3469(区间dp)相关的知识,希望对你有一定的参考价值。
题目翻译:当我们专注于解决问题时,我们通常宁愿呆在电脑前而不是外出吃午饭。在这个时候,我们可能会要求提供食物。
假设有N个人生活在一条直线的街道上,它只是位于X坐标轴上。第i个人的坐标是Xi米。在街上有一个外围餐厅,坐标X米。在午餐时间的一天,每个人同时从餐厅接受订单。作为餐厅的工作人员,您需要从餐厅开始,向N人送食物,然后回到餐厅。你的速度是每分钟V-1米。
你知道N人有不同的个性;因此他们对食物到来的时间有不同的感觉。他们的感受是通过不满指数衡量的。一开始,每个人的不满指数为0.在等待食物时,第i个人将获得每分钟的双不满指数。
如果一个人的不满指数过高,他将不再购买你的食物了。因此,您需要尽可能降低所有人的不满指数之和,以便最大化您的收入。你的任务是找到不满指数的最小总和。
输入
输入包含多个测试用例,用空行分隔。每种情况以三个整数N(1 <= N <= 1000),V(V> 0),X(X> = 0)开始,然后是N行。每行包含两个整数Xi(Xi> = 0),Bi(Bi> = 0),如上所述。
您可以放心地假设输入和输出中的所有数字都小于2^31 - 1。
请处理到文件结尾。
产量
对于每个测试用例,请输出一个数字,这是不满指数的最小总和。每行一个测试用例。(来自谷歌翻译)
输入:
5 1 0
1 1
2 2
3 3
4 4
5 5
输出:
55
解题思路:首先按每个客人的坐标位置排序,此时定义某个状态dp【i】【j】为经过坐标轴上第i~j号位置产生的“不满”值,那么此时将产生一个问题:经过i~j,我们此时是在的i号位置还是第j号位置的呢?所以我们可以给这个状态加一维,此时dp【i】【j】【0】为经过i~j,此时在i号位置,dp【i】【j】【1】为经过i~j,此时在第j号位置。然后可以得到状态转移方程:
dp【i】【j】【0】=min(dp【i】【j】【0】,dp【i+1】【j】【0】+代价)(即此时我们从i+1号位置到达i号位置,代价为 时间*还没有经过的位置产生的“不满”值(即1~i号位置跟j+1~n号位置产生的“不满”值))
dp【i】【j】【0】=min(dp【i】【j】【0】,dp【i+1】【j】【1】+代价)(此时我们从第j号位置到达i号位置)
dp【i】【j】【1】=min(dp【i】【j】【1】,dp【i】【j-1】【1】+代价)(此时我们从第j-1号位置到达j号位置)
dp【i】【j】【1】=min(dp【i】【j】【1】,dp【i】【j-1】【0】+代价)(此时我们从第i号位置到达j号位置)
最后的答案就是经过1~n号位置所产生最小的“不满值”,即min(dp【1】【n】【0】,dp【1】【n】【1】);
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<stack> #include<cstdio> #include<map> #include<set> #include<string> #include<queue> using namespace std; #define inf 0x3f3f3f3f #define ri register int typedef long long ll; inline ll gcd(ll i,ll j){ return j==0?i:gcd(j,i%j); } inline ll lcm(ll i,ll j){ return i/gcd(i,j)*j; } inline void output(int x){ if(x==0){putchar(48);return;} int len=0,dg[20]; while(x>0){dg[++len]=x%10;x/=10;} for(int i=len;i>=1;i--)putchar(dg[i]+48); } inline void read(int &x){ char ch=x=0; int f=1; while(!isdigit(ch)){ ch=getchar(); if(ch==‘-‘){ f=-1; } } while(isdigit(ch)) x=x*10+ch-‘0‘,ch=getchar(); x=x*f; } const int maxn=1e3+5; struct st{ int x,w; bool operator < (const st tem)const{ return x<tem.x; } }stm[maxn]; int sum[maxn]; int dp[maxn][maxn][2]; int n,v,x; int count(int l,int r){ if(l<=r) return sum[r]-sum[l-1]; return 0; } void solve(){ memset(dp,0x3f,sizeof(dp)); int res; for(int i=1;i<=n+1;i++){ if(stm[i].x==x){ res=i;//找到起点 break; } } dp[res][res][0]=dp[res][res][1]=0; for(int i=res;i>=1;i--){ for(int j=res;j<=n+1;j++){ int tem=count(1,i-1)+count(j+1,n+1); if(i==j) continue; dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(stm[i+1].x-stm[i].x)*(tem+stm[i].w)); dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(stm[j].x-stm[i].x)*(tem+stm[i].w)); dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(stm[j].x-stm[i].x)*(tem+stm[j].w)); dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(stm[j].x-stm[j-1].x)*(tem+stm[j].w)); } } return ; } int main(){ while(scanf("%d%d%d",&n,&v,&x)!=EOF){ memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++){ scanf("%d%d",&stm[i].x,&stm[i].w); } stm[n+1].x=x; stm[n+1].w=0; sort(stm+1,stm+n+2); for(int i=1;i<=n+1;i++){ sum[i]=sum[i-1]+stm[i].w; } solve(); printf("%d ",min(dp[1][n+1][0],dp[1][n+1][1])*v); } return 0; }
以上是关于Food Delivery ZOJ - 3469(区间dp)的主要内容,如果未能解决你的问题,请参考以下文章
Food Delivery ZOJ - 3469 (区间dp)