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\n",min(dp[1][n+1][0],dp[1][n+1][1])*v);
	}
	return 0;
}

  

posted @ 2019-04-07 23:31  风雨兼程-zhi  阅读(172)  评论(0编辑  收藏  举报