【题目描述】
铁路线上有n(2 ≤ n ≤ 10000)个火车站,每个火车站到该线路的首发火车站距离都是已知的。任意两站之间的票价如下所示:
当 $0 < x ≤ L_1 ,\ price = C_1$ 当 $L_1 < x ≤ L_2,\ price = C_2$ 当 $L_2 < x ≤ L_3,\ price = C_3$
其中 $L_1,L_2,L_3,C_1,C_2,C_3$ 都是已知的正整数, 且$1≤L_1 < L_2 < L_3 ≤ 10^9, 1 ≤ C_1 < C_2 < C_3 ≤ 10^9$。 显然若两站之间的距离大于L3,那么从一站到另一站至少要买两张票。
注意:每一张票在使用时只能从一站开始到另一站结束。
对于给出的起点和终点,求出最省钱的方案。
【题目链接】
Tyvj 3317 火车票(清新版题面) CodeVS 1349 板猪的火车票 (恶搞版题面)
【解题思路】
划分DP,设$f[i]$表示从起点$s$到$i$的最小花费。
转移: $$ f[i] = min\{\ f[k] + cost(k, i)\ \}\ k \in [s, i)\ \&\& \ dist(k, i) ≤ L3 $$ 其中$dist(i, j)$表示$i$到$j$的距离,$cost(i, j)$表示$i$到$j$的车票价格,显然都可以$O(1)$计算。
转移思路很简单,就是枚举从火车站k到这儿来,取最小花费。
边界: $$ f[s] = 0 $$
【AC代码】
因为心情好,于是就写记忆化搜索啦。~~(似乎并没有什么关联)~~
#include <cstdio>
#include <algorithm>
#include <climits>
#define MAXN 10000
int a[MAXN];
int n, s, t;
int L1, L2, L3, C1, C2, C3;
int f[MAXN];
bool visited[MAXN];
inline int cost(int i, int j){
int dist = a[j] - a[i];
if (dist > L3) return -1;
else if (dist > L2) return C3;
else if (dist > L1) return C2;
else return C1;
}
int search(int v){
int &ans = f[v];
if(visited[v]) return ans;
else visited[v] = true;
if(v == s) ans = 0;
else{
ans = INT_MAX;
for(int k = s; k < v; k++){
int c = cost(k, v);
if(c == -1) continue;
else ans = std::min(ans, search(k) + c);
}
}
return ans;
}
int main(){
scanf("%d %d %d %d %d %d", &L1, &L2, &L3, &C1, &C2, &C3);
scanf("%d%d%d", &n, &s, &t), s--, t--;
for(int i = 1; i < n; i++) scanf("%d", a + i);
printf("%d", search(t));
return 0;
}
就是这样啦