题目描述:
有N个火车站,有三种价格的票(0<C1<C2<C3<10^9),对应三种距离(0<L1<L2<L3<10^9).相邻两站间的距离<=L3。给出A, B(起始站和终点站),N(总的火车站数),dis[2],dis[3],dis[4],…,dis[N](该线路上的第一个站,到第2站,第3站,……,第N站的距离)。求乘客从A到B站的最小花费。
思路:
网上有用动态规划来求的,但根据最优性原理,每站都要遍历,不可跳过。
因此,我选择用贪心算法来求。即从起点A开始,算三种票最远可以坐到终点B范围内的哪一站,然后计算目前花费并比较是否变少。如此从A到B遍历计算(过程中有的站经判断可直接跳过,不用计算)。到B时即可得到结果。
学习与体会:
本题数据大,要用long long(等价_int64),其输出用"%lld"或"%l64d"。另外long long int就是long long。
如果还要求输出线路,则可以在结构体中加一个next,表下一站。计算费用时填入下一站。则可以按此输出线路。
本题用贪心算法,既可以从起点算到终点,也可以从终点算到起点。
从起点到终点的贪心算法:
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <climits>
using namespace std;
//火车站结构体
struct TrainStation{
//long long int next; //下一站
long long int cost; //该站到终点站的最小花费
long long int dis; //到第一站距离
};
int main(){
TrainStation station[30000];//其从下标1开始使用
long long int L[3],C[3]; //三种票的距离和票价
long long int A,B,N; //起始站,终点站,火车站数
int i,j,k;
//输入三种票的距离和票价
while(scanf("%lld %lld %lld %lld %lld %lld",&L[0],&L[1],&L[2],&C[0],&C[1],&C[2])!=EOF){
memset(station,0,30000*sizeof(TrainStation));
scanf("%lld %lld",&A,&B); //输入起始站,终点站
if(A>B){ //保证A小B大
A=A^B; B=A^B; A=A^B;
}
scanf("%lld",&N); //输入火车站数
station[1].dis=0; //输入距离
for(i=2;i<=N;i++){
scanf("%lld",&station[i].dis);
}
//计算最小花费
if(A==B) //起点和终点同站
printf("0\n");
else{ //起点和终点不同站
for(i=A;i<B;i++){ //起点到终点遍历计算
if(i!=A && station[i].cost==0) //除起点站,其他站若遍历到它时,cost还是0,表示便宜的花费不包括在该站停留
continue;
else{ //cost不为0,表示便宜的花费可能包括在该站停留
for(j=0;j<3;j++){ //计算3种票从该站最多可往后坐到哪站,并计算出费用
k=i+1; //可到达的后面的站
while(k<=B && (station[k].dis-station[i].dis)<=L[j])
k++;
k--;
if(k==i) //用该种票不可到后一站
continue;
else{ //用该种票可到后一站
//费用减少了(或k站还未被规划进最小花费路线),则替换(或把k站规划进来)
if((C[j]+station[i].cost)<station[k].cost || station[k].cost==0){
station[k].cost=C[j]+station[i].cost;
//station[k].next=i;
}
}
}
}
}
//输出最小花费
printf("%lld\n",station[B].cost);
}
}
return 0;
}
从终点到起点的贪心算法:
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <climits>
using namespace std;
//火车站结构体
struct TrainStation{
//long long int next; //下一站
long long int cost; //该站到终点站的最小花费
long long int dis; //到第一站距离
};
int main(){
TrainStation station[30000];//其从下标1开始使用
long long int L[3],C[3]; //三种票的距离和票价
long long int A,B,N; //起始站,终点站,火车站数
int i,j,k;
//输入三种票的距离和票价
while(scanf("%lld %lld %lld %lld %lld %lld",&L[0],&L[1],&L[2],&C[0],&C[1],&C[2])!=EOF){
memset(station,0,30000*sizeof(TrainStation));
scanf("%lld %lld",&A,&B); //输入起始站,终点站
if(A>B){ //保证A小B大
A=A^B; B=A^B; A=A^B;
}
scanf("%lld",&N); //输入火车站数
station[1].dis=0; //输入距离
for(i=2;i<=N;i++){
scanf("%lld",&station[i].dis);
}
//计算最小花费
if(A==B) //起点和终点同站
printf("0\n");
else{ //起点和终点不同站
for(i=B;i>A;i--){ //终点到起点遍历计算
if(i!=B && station[i].cost==0) //除终点站,其他站若遍历到它时,cost还是0,表示便宜的花费不包括在该站停留
continue;
else{ //cost不为0,表示便宜的花费可能包括在该站停留
for(j=0;j<3;j++){ //计算3种票从该站最多可往前坐到哪站,并计算出费用
k=i-1; //可到达的前面的站
while(k>=A && (station[i].dis-station[k].dis)<=L[j])
k--;
k++;
if(k==i) //用该种票不可到前一站
continue;
else{ //用该种票可到前一站
//费用减少了(或k站还未被规划进最小花费路线),则替换(或把k站规划进来)
if((C[j]+station[i].cost)<station[k].cost || station[k].cost==0){
station[k].cost=C[j]+station[i].cost;
//station[k].next=i;
}
}
}
}
}
//输出最小花费
printf("%lld\n",station[A].cost);
}
}
return 0;
}