本文主要是介绍zoj 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 2^31 - 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
中文:
在一个一维数轴上,你开了一家外卖店,数轴上还有居民,你现在需要给不同位置的居民送餐,你的送餐速度是v,每户居民有两个值,分别是在数轴上的坐标xi和容忍度bi,居民的容忍度每隔一分钟上涨bi,求全部居民送餐后,总的容忍度最小。
代码:
#include<bits/stdc++.h>using namespace std;
#define INF 0x3f3f3f3f
#define mem0(x) memset(x,0,sizeof(x))
#define memI(x) memset(x,INF,sizeof(x))
const int maxn = 1002;typedef pair<int,int> pii;
pii ps[maxn];
int n,v,x;
int dp[maxn][maxn][2];
int sum[maxn];int main()
{ios::sync_with_stdio(false);while(cin>>n>>v>>x){for(int i=1;i<=n;i++)cin>>ps[i].first>>ps[i].second;ps[++n].first=x;ps[n].second=0;sort(ps+1,ps+1+n,[](const pii& p1,const pii &p2){ return p1.first<p2.first;});mem0(sum);memI(dp);int start;for(int i = 1;i<=n;++i){sum[i]=sum[i-1]+ps[i].second;if(ps[i].first==x)start=i;}dp[start][start][0]=dp[start][start][1]=0;for(int i = start;i>=1;i--){for(int j=start;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])*(ps[i+1].first-ps[i].first));dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(sum[n]-sum[j]+sum[i])*(ps[j].first-ps[i].first));dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(sum[n]-sum[j-1]+sum[i-1])*(ps[j].first-ps[i].first));dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(sum[n]-sum[j-1]+sum[i-1])*(ps[j].first-ps[j-1].first));}}cout<<v*min(dp[1][n][0],dp[1][n][1])<<endl;}return 0;
}
思路:
太笨,自己没想出来,想出来个思路还是错的 -_-
首先没想出来为什么这题为什么可以使用区间模型去求解,要不是做的是区间dp的练习场,自己肯定不会把这个题目想到区间dp模型上去。
另外,此题的状态设置与一般的状态设置有些区别,本题目状态方程为
d p [ i ] [ j ] [ 2 ] dp[i][j][2] dp[i][j][2]表示在区间i到j这段区间送餐完成后,留在左侧或右侧的全局容忍度和最小,从状态转移方程就能看出来,与一般的dp状态转移方程表达的结果不同。
这题为什么可以用区间dp来解答?
个人理解关键在于如何描述这个送货员的状态,送货员在每次送餐后一定是停留在刚送完的餐的位置,那么有两种可能,一种是从相邻的位置坐标到最终位置;另一种是从较远的位置送来,即刚刚送完餐后折返到另一头。
所以需要使用区间dp来描述状态
那么状态转移方程可以表示如下
其中 d p [ i ] [ j ] 0 ] dp[i][j]0] dp[i][j]0]表示在区间i到j送餐完成后留在左端点i的全局最小容忍度,那么转移状态按照上面说的有两种,一种是从i+1到i 另一种是从j到i,对应的状态转移表达式如下
d p [ i ] [ j ] [ 0 ] = m i n ( d p [ i ] [ j ] [ 0 ] , d p [ i + 1 ] [ j ] [ 0 ] + ( s u m [ n ] − s u m [ j ] + s u m [ i ] ) ∗ ( p s [ i + 1 ] . f i r s t − p s [ i ] . f i r s t ) ) dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(sum[n]-sum[j]+sum[i])*(ps[i+1].first-ps[i].first)) dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(sum[n]−sum[j]+sum[i])∗(ps[i+1].first−ps[i].first))
d p [ i ] [ j ] [ 0 ] = m i n ( d p [ i ] [ j ] [ 0 ] , d p [ i + 1 ] [ j ] [ 1 ] + ( s u m [ n ] − s u m [ j ] + s u m [ i ] ) ∗ ( p s [ j ] . f i r s t − p s [ i ] . f i r s t ) ) dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(sum[n]-sum[j]+sum[i])*(ps[j].first-ps[i].first)) dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(sum[n]−sum[j]+sum[i])∗(ps[j].first−ps[i].first))
同理留在右端点
d p [ i ] [ j ] [ 1 ] = m i n ( d p [ i ] [ j ] [ 1 ] , d p [ i ] [ j − 1 ] [ 0 ] + ( s u m [ n ] − s u m [ j − 1 ] + s u m [ i − 1 ] ) ∗ ( p s [ j ] . f i r s t − p s [ i ] . f i r s t ) ) dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(sum[n]-sum[j-1]+sum[i-1])*(ps[j].first-ps[i].first)) dp[i][j][1]=min(dp[i][j][1],dp[i][j−1][0]+(sum[n]−sum[j−1]+sum[i−1])∗(ps[j].first−ps[i].first))
d p [ i ] [ j ] [ 1 ] = m i n ( d p [ i ] [ j ] [ 1 ] , d p [ i ] [ j − 1 ] [ 1 ] + ( s u m [ n ] − s u m [ j − 1 ] + s u m [ i − 1 ] ) ∗ ( p s [ j ] . f i r s t − p s [ j − 1 ] . f i r s t ) ) dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(sum[n]-sum[j-1]+sum[i-1])*(ps[j].first-ps[j-1].first)) dp[i][j][1]=min(dp[i][j][1],dp[i][j−1][1]+(sum[n]−sum[j−1]+sum[i−1])∗(ps[j].first−ps[j−1].first))
这篇关于zoj 3469的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!