ZOJ 3469 Food Delivery (区间DP,经典)

 

 

 

题意:

  在x轴上有一家外卖餐馆,有n个顾客站在x轴上不同坐标上且叫了外卖,每个人的脾气不同,每1分钟没有收到外卖就会增加Fi点愤怒值,而外卖小哥的车是有速度的v-1/分钟,问怎样的送餐次序会让所有顾客的愤怒值之和最小?输出愤怒值之和!

 

 

思路:

  此题是很经典了,比较现实的模型。

  随便画画就知道小哥可以一下子往左一下子往右走,往返多次也是有可能的,取决于顾客的愤怒系数Fi。那么在考虑一个区间[L,R]时,其任一子区间都必须是已经被考虑过了。现在考虑区间[L,R]可以转移到哪里,明显可以分别转移到[L-1,R]和[L,R+1],也就是往区间外送去1个人的外卖。由于送完区间[L,R]所有外卖后可能停在左/右边,得到的DP值不同,所以可以增加1维来区分送完后停的位置,设为dp[L][R][0/1]来记录愤怒之和。

  这样还没有完,如果仅考虑当前区间[L,R]的顾客的愤怒值之和的话,无论怎样记录还是难以实现转移(这也是比较巧的地方)。但是如果你将其他未送达的顾客的愤怒值也先算进dp值的话就好转移了,比如区间[L,R]转移到[L,R+1],那么[1,L-1]和[R+2,n]这些顾客就还在等外卖,每过1分钟他们的愤怒值也在增加,可以加到[L,R+1]的dp值进行考虑。

  有没有可能dp[L][R][0]会转移到dp[L][R+1][0]?也就是从L走到R+1后还回到L处。经过推算,并不需要这样,不是很难想的。

 

 1 //#include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <map>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <iostream>
10 #define pii pair<int,int>
11 #define INF 0x3f3f3f3f
12 #define LL long long
13 using namespace std;
14 const double PI  = acos(-1.0);
15 const int N=1010;
16 struct node
17 {
18     int x, f;
19 }p[N];
20 int dp[N][N][2], sum[N];
21 int n, V, x, pos;
22 inline int cmp(node a,node b){return a.x<b.x;}
23 
24 void init(int pos)
25 {
26     sum[0]=0;
27     for(int i=1; i<=n; i++)    sum[i]=sum[i-1]+p[i].f;
28 
29     for(int i=1; i<=n; i++)     //初始化
30         for(int j=i; j<=n; j++)
31             dp[i][j][0]=dp[i][j][1]=INF;
32     dp[pos][pos][0]=dp[pos][pos][1]=0;
33 }
34 
35 int cal(int pos)
36 {
37     for(int j=pos; j<=n; j++)
38     {
39         for(int i=pos; i>0; i--)
40         {
41             int f=sum[i-1]+sum[n]-sum[j];   //f值之和*
42             int L=dp[i][j][0], R=dp[i][j][1];
43 
44             dp[i-1][j][0]=min(dp[i-1][j][0], L+f*(p[i].x-p[i-1].x));    //往左
45             dp[i-1][j][0]=min(dp[i-1][j][0], R+f*(p[j].x-p[i-1].x));
46 
47             dp[i][j+1][1]=min(dp[i][j+1][1], L+f*(p[j+1].x-p[i].x));    //往右
48             dp[i][j+1][1]=min(dp[i][j+1][1], R+f*(p[j+1].x-p[j].x));
49         }
50     }
51     return min(dp[1][n][0], dp[1][n][1])*V;
52 }
53 
54 int main()
55 {
56     //freopen("input.txt", "r", stdin);
57     while(~scanf("%d%d%d",&n,&V,&x))
58     {
59         for(int i=1; i<=n; i++)
60             scanf("%d%d", &p[i].x, &p[i].f);
61 
62         p[++n].x=x, p[n].f=0;   //添加餐馆
63         sort(p+1, p+n+1, cmp);
64 
65         for(int i=1; i<=n; i++)
66         {
67             if(p[i].x==x)   //找到餐馆
68             {
69                 init(i);
70                 cout<<cal(i)<<endl;
71                 break;
72             }
73         }
74     }
75     return 0;
76 }
AC代码

 

posted @ 2015-09-30 15:16  xcw0754  阅读(392)  评论(0编辑  收藏  举报