Food Delivery ZOJ - 3469 区间dp

//dp[i][j][0/1] 表示送完区间 [i, j] 后,且外卖员在 i/j 点 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1100;
const int inf=0x3f3f3f3f;
struct node{
	int x,b;
}s[N];
ll dp[N][N][2];
ll sum[N];
bool cmp(node a,node b)
{
	return a.x<b.x;
}
int main()
{
	int n,v,x;
	while(cin>>n>>v>>x)
	{
		//输入位置和怒气
		for(int i=1;i<=n;i++)
			cin>>s[i].x>>s[i].b;
		//把外卖员的加进去 
		s[++n].x=x,s[n].b=0;
		sort(s+1,s+1+n,cmp);
		for(int i=1;i<=n;i++)
			sum[i]=sum[i-1]+s[i].b;
		//找起始位置 
		int start=0;
		while(s[++start].x != x);
		//初始化 
		memset(dp, inf, sizeof(dp));
		dp[start][start][0] = dp[start][start][1] = 0;
		//向两边延申 
		for(int i = start; i >= 1; --i) {
			for(int j = start; j <= n; ++j) {
				//送完i到j			在i个位置	 									剩下的人等的时间 
				dp[i][j][0] = min(dp[i][j][0], dp[i + 1][j][0] + (s[i + 1].x - s[i].x) * (sum[n] - (sum[j] - sum[i])));
				dp[i][j][0] = min(dp[i][j][0], dp[i + 1][j][1] + (s[j].x - s[i].x) * (sum[n] - (sum[j] - sum[i])));
				dp[i][j][1] = min(dp[i][j][1], dp[i][j - 1][0] + (s[j].x - s[i].x) * (sum[n] - (sum[j - 1] - sum[i - 1])));
				dp[i][j][1] = min(dp[i][j][1], dp[i][j - 1][1] + (s[j].x - s[j - 1].x) * (sum[n] - (sum[j - 1] - sum[i - 1])));
			}
		}
		printf("%lld\n", min(dp[1][n][0], dp[1][n][1]) * v);
	 } 
	 return 0;
}
posted @ 2020-03-12 15:22  晴屿  阅读(75)  评论(0编辑  收藏  举报