zoj3469——区间dp好题

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3469

When we are focusing on solving problems, we usually prefer to stay in front of computers rather than go out for lunch. At this time, we may call for food delivery.

Suppose there are N people living in a straight street that is just lies on an X-coordinate axis. The ith person's coordinate is Xi meters. And in the street there is a take-out restaurant which has coordinates X meters. One day at lunchtime, each person takes an order from the restaurant at the same time. As a worker in the restaurant, you need to start from the restaurant, send food to the N people, and then come back to the restaurant. Your speed is V-1 meters per minute.

You know that the N people have different personal characters; therefore they have different feeling on the time their food arrives. Their feelings are measured by Displeasure Index. At the beginning, the Displeasure Index for each person is 0. When waiting for the food, the ith person will gain Bi Displeasure Index per minute.

If one's Displeasure Index goes too high, he will not buy your food any more. So you need to keep the sum of all people's Displeasure Index as low as possible in order to maximize your income. Your task is to find the minimal sum of Displeasure Index.

 

Input

 

The input contains multiple test cases, separated with a blank line. Each case is started with three integers N ( 1 <= N <= 1000 ), V ( V > 0), X ( X >= 0 ), then N lines followed. Each line contains two integers Xi ( Xi >= 0 ), Bi ( Bi >= 0), which are described above.

You can safely assume that all numbers in the input and output will be less than 231 - 1.

Please process to the end-of-file.

 

Output

 

For each test case please output a single number, which is the minimal sum of Displeasure Index. One test case per line.

 

Sample Input

 

5 1 0
1 1
2 2
3 3
4 4
5 5
 

 

Sample Output

 

55

 

题目翻译:

当我们专注于解决问题时,我们通常宁愿呆在电脑前,也不愿出去吃午饭。在这个时候,我们可以要求运送粮食。‎

‎假设有N‎‎个人住在一条直线上,只是位于X坐标轴上。‎‎Ith‎‎人的坐标是X ‎‎i‎‎米。在街上有一个带‎‎坐标X‎‎米的外带餐厅。一天午餐时间,每个人同时从餐厅取订单。作为餐厅的工人,你需要从餐厅开始,给N人送食物,然后回到餐厅。 ‎‎您的速度是‎‎V‎‎-1‎‎米/分钟。‎

‎你知道N人有不同的‎‎个人性格;因此,他们有不同的感觉,他们的食物到达的时间。他们的感受是由‎‎不快乐指数‎‎来衡量的。开始时,每个人的‎‎不快乐指数‎‎为 0。等待食物时,i‎‎人每分钟‎‎将获得 B ‎‎i‎‎ ‎‎ ‎‎不快指数。‎‎ ‎

‎如果一个人‎‎的不满指数‎‎过高,他不会再买你的食物了。因此,你需要保持所有的人‎‎的不满指数‎‎的总和尽可能低,以最大限度地提高你的收入。你的任务是‎‎找到"不快乐指数"‎‎的最小总和。‎

 

‎输入‎

 

‎输入包含多个测试用例,用空行分隔。每个案例以三个整数‎‎N‎‎ ( 1 <= ‎‎N‎‎ <= 1000)、 ‎‎V‎‎ (V > 0)、X (X;= 0) 开始,然后跟随‎‎N‎‎行。 ‎‎ ‎‎ ‎‎每行包含两个整数‎‎X‎‎i‎‎ ‎‎ ( ‎‎X‎‎i‎‎ ‎‎ >= 0), ‎‎B‎‎i‎‎ ‎‎ ( ‎‎B‎‎i‎‎ ‎‎ >= 0), 上面描述.‎

‎您可以安全地假定输入和输出中的所有数字都小于 2‎‎31‎‎ - 1。‎

‎请处理到文件结尾。‎

 

‎输出‎

 

‎对于每个测试用例,请输出一个数字,‎‎这是"不快乐指数"‎‎的最小和总和。每行一个测试用例。

 

这个题的状态转移方程很难想,其实一开始我想的是能不贪心的去做,最后发现好像不行,看的网上的题解才懂了。

我们可以把餐厅的位置也弄进去,都存进一个数组中,按照x的位置排序,找出餐厅的位置,再进行区间dp;

重点和难点在于区间dp的状态和状态转移方程。

状态:dp[i][j][0]:表示送完i到j的订单并最后停留在左端点

dp[i][j][1]:表示送完i到j的订单后最后停留在右端点

状态转移方程这里就不给了,可以参考代码,挺难想的,不过自己应该能弄懂。

#include <iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int INF=0x3f3f3f3f;
struct Point{
	int x,b;
}p[1005]; 
int dp[1005][1005][2];
int sum[1005];
bool cmp(Point m,Point n){
	return m.x<n.x;
}
int main(int argc, char** argv) {
	int n,v,x;
	while(~scanf("%d%d%d",&n,&v,&x)){
		for(int i = 1;i<=n;++i)
			scanf("%d%d",&p[i].x,&p[i].b);
		p[++n].x=x;
		p[n].b=0;
		sort(p+1,p+1+n,cmp);//按照x位置排序 
		sum[0]=0;
		int pos;
		for(int i = 1;i<=n;++i){//找到餐厅的位置 
			sum[i]=sum[i-1]+p[i].b;
			if(p[i].x==x) pos=i;
		}
		memset(dp,INF,sizeof(dp));
		dp[pos][pos][0]=dp[pos][pos][1]=0;
		for(int i = pos;i>=1;i--){//枚举左边端点 
			for(int j=pos;j<=n;++j){//枚举右边端点 
				if(i==j) continue;
				dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(sum[n]-sum[j]+sum[i])*(p[i+1].x-p[i].x));//最后面一部分表示与当前区间无关的其他区间,因为没有送,所以要有不快乐值的增加。 
				dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(sum[n]-sum[j]+sum[i])*(p[j].x-p[i].x));
				
				dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(sum[n]-sum[j-1]+sum[i-1])*(p[j].x-p[i].x));
				dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(sum[n]-sum[j-1]+sum[i-1])*(p[j].x-p[j-1].x));
				
			}
		}
		printf("%d\n",v*min(dp[1][n][0],dp[1][n][1]));//最后在乘于v,不然可能会中间结果溢出 
	}
	return 0;
}

 

上一篇:python 学习day 7


下一篇:python class的使用