清华 2011 最小花费

题目描述:

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站的距离)。求乘客从AB站的最小花费。

思路:

网上有用动态规划来求的,但根据最优性原理,每站都要遍历,不可跳过。

因此,我选择用贪心算法来求。即从起点A开始,算三种票最远可以坐到终点B范围内的哪一站,然后计算目前花费并比较是否变少。如此从AB遍历计算(过程中有的站经判断可直接跳过,不用计算)。到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;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值