题目1086:最小花费 ( 动态规划 )
题目1086:最小花费
时间限制:1 秒
内存限制:32 兆
特殊判题:否
提交:3544
解决:730
- 题目描述:
-
在某条线路上有N个火车站,有三种距离的路程,L1,L2,L3,对应的价格为C1,C2,C3.其对应关系如下:距离s 票价0<S<=L1 C1L1<S<=L2 C2L2<S<=L3 C3输入保证0<L1<L2<L3<10^9,0<C1<C2<C3<10^9。每两个站之间的距离不超过L3。当乘客要移动的两个站的距离大于L3的时候,可以选择从中间一个站下车,然后买票再上车,所以乘客整个过程中至少会买两张票。现在给你一个 L1,L2,L3,C1,C2,C3。然后是A B的值,其分别为乘客旅程的起始站和终点站。然后输入N,N为该线路上的总的火车站数目,然后输入N-1个整数,分别代表从该线路上的第一个站,到第2个站,第3个站,……,第N个站的距离。根据输入,输出乘客从A到B站的最小花费。
- 输入:
-
以如下格式输入数据:L1 L2 L3 C1 C2 C3A BNa[2]a[3]……a[N]
- 输出:
-
可能有多组测试数据,对于每一组数据,根据输入,输出乘客从A到B站的最小花费。
- 样例输入:
-
1 2 3 1 2 3 1 2 2 2
- 样例输出:
-
2
- 来源:
- 2011年清华大学计算机研究生机试真题
- 题意:
- 有C1、C2、C3三种票价,分别对应不同长度的路程,RT。
- 现在有n个城市排成一列,已知每个城市到第一个城市的距离且保证相邻两个城市间的距离不大于L3。
- 问从起点城市a到终点城市b最少需要多少钱。
- 分析:
- (思路1)
- 对于任意一段从 i 城市 到 j 城市 的路,dp[i][j]表示最小花费
- 1、如果<=L1则需要C1
- 2、如果>L1 && <=L2 则需要C2
- 3、如果>L2 && <=L3 则需要C3
- 4、也可以看这段路通过划分成两段的和的花费是否更小
- dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j])
- 于是就是求上述4种情况的最小值。
- 但是,注意几点:
- 1、递推的顺序,关于第4个递推必须是要知道了小段的花费才能推到由小段组成的大段的花费。
- 故用一维枚举间隔长度,第二维枚举起点。先从小段更新再更新大段。
- 不能for(i=1..n)
- for(j=i+1...n)
- 这样,有些小段还没求就要求大段,所以得不到想要的结果。
- 2、由于是min取最小值,所以初始化是INF无穷大。
- 当起点a = 终点b时,如果不特判,就会输出INF(因为间隔为0的时候没有写在循环中特判)
- 故只要单独特判(a==b)输出0就可以了。。这样比在循环中特判简单
- (我开始就是WA在这两处啊。。。逃)
-
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<set> 11 12 using namespace std; 13 14 typedef long long ll; 15 16 ll L1,L2,L3,C1,C2,C3; 17 ll dis[1010],dp[1010][1010]; 18 19 int main() 20 { 21 int n,a,b; 22 while(~scanf("%lld%lld%lld%lld%lld%lld",&L1,&L2,&L3,&C1,&C2,&C3)) 23 { 24 scanf("%d%d",&a,&b); 25 if(a>b) 26 { 27 int tmp = a; 28 a = b; 29 b = tmp; 30 } 31 scanf("%d",&n); 32 dis[1] = 0; 33 for(int i=2;i<=n;i++) 34 scanf("%lld",&dis[i]); 35 // if(a==b) //特判起点=终点 36 // { 37 // printf("0\n"); 38 // continue; 39 // } 40 memset(dp,0x3f,sizeof(dp)); 41 for(int k=0;k<n;k++) 42 { 43 for(int i=1;i<=n;i++) 44 { 45 if(i+k>n) continue; 46 ll x = dis[i+k]-dis[i]; 47 if(k==0) dp[i][i] = 0; 48 else 49 { 50 if(x<=L1) 51 dp[i][i+k] = min(dp[i][i+k],C1); 52 else if(x>L1 && x<=L2) 53 dp[i][i+k] = min(dp[i][i+k],C2); 54 else if(x>L2 && x<=L3) 55 dp[i][i+k] = min(dp[i][i+k],C3); 56 for(int j=i+1;j<i+k;j++) 57 dp[i][i+k] = min(dp[i][i+k],dp[i][j]+dp[j][i+k]); 58 } 59 60 } 61 } 62 printf("%lld\n",dp[a][b]); 63 } 64 return 0; 65 }
(思路2)
dp[i]表示从起点到 i 城市 需要的最小花费。它可能是由前面与它小于等于L3或者L2或者L1距离的 城市j 的dp[j]+cost(i,j)得到(取所有情况的最小值)
cost(i,j)就是根据距离标准为C1、C2或者C3.
这里求a到b的最小花费就要取a为起点,答案为dp[b]
误区:
不能以1为起点递推出dp[i](i=1...n),再用dp[b]-dp[a]作答案
如:
/*
1 2 3 2 3 4
2 3
3
1 2*/
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<set> 11 12 using namespace std; 13 14 typedef long long ll; 15 16 ll L1,L2,L3,C1,C2,C3; 17 ll dis[1010],dp[1010]; 18 19 ll solve(int i,int j) 20 { 21 if(dis[i]-dis[j]<=L1) return C1; 22 else return dis[i]-dis[j]<=L2?C2:C3; 23 } 24 25 int main() 26 { 27 int n,a,b; 28 while(~scanf("%lld%lld%lld%lld%lld%lld",&L1,&L2,&L3,&C1,&C2,&C3)) 29 { 30 scanf("%d%d",&a,&b); 31 if(a>b) 32 { 33 int tmp = a; 34 a = b; 35 b = tmp; 36 } 37 scanf("%d",&n); 38 dis[1] = 0; 39 for(int i=2;i<=n;i++) 40 scanf("%lld",&dis[i]); 41 42 dp[a] = 0; 43 for(int i=a+1;i<=b;i++) 44 { 45 ll tmp = 2211686018427387904; 46 for(int j=i-1;j>=a && dis[i]-dis[j]<=L3;j--) 47 { 48 tmp = min(tmp,dp[j]+solve(i,j)); 49 } 50 dp[i] = tmp; 51 } 52 printf("%lld\n",dp[b]); 53 } 54 return 0; 55 }