PAT A1033 To Fill or Not To Fill 看了书才知道自己的思维不严谨,即使算法大概对,还少了很多

//ac全部正确!果然是晴神宝典 
//有时候程序并没有问题,但是编译器就是会报错时候返回为1,说什么无法打开输出文件,这时把所有运行的本程序关闭,再输出文件刷新一下 
//我的错点:选出最近的油价低于当前油价的加油站 
//算上最后一个加油站,就是从[0,n],所以while(now<n)//每次循环将选出下一个需要到达的加油站. 
//if(nowTank<need){//尤其注意,这里也是要判断的,而我自己忘记判断了 
#include<cstdio>
#include<cstring>
#include<algorithm>
//#define LOCAL //这里如果不注释会出现段错误或者答案错误 
using namespace std;
const int maxn=510;
const int INF=1000000000; 
struct station{
	double price,dis;//价格、与起点之间的距离 
}st[maxn];
bool cmp(station a,station b){
	return a.dis<b.dis;
}
int main(){
	#ifdef LOCAL
	freopen("A1033data.in","r",stdin);
	freopen("A1033data.out","w",stdout);
	#endif
	int n;
	double Cmax,D,Davg;
	scanf("%lf%lf%lf%d",&Cmax,&D,&Davg,&n);
	for(int i=0;i<n;i++){
		scanf("%lf%lf",&st[i].price,&st[i].dis);
	}
	st[n].price=0.0;
	st[n].dis=D;
	sort(st,st+n,cmp);//将所有加油站按照距离从小到大排序
	/*for(int i=0;i<=n;i++){
		printf("%d,%.3f %.0f\n",i,st[i].price,st[i].dis);
	} */
	if(st[0].dis!=0){
		printf("The maximum travel distance = 0.00\n");
	}
	else{
		int now=0;//当前所处的加油站编号
		//总花费、当前油量、满油行使的距离
		double ans=0,nowTank=0,MAX=Cmax*Davg;//Max是满油行使的距离 
		while(now<n){//每次循环将选出下一个需要到达的加油站
			//选出从当前加油站满油能到达范围内的最近的油价低于当前油价的加油站 
			//如果没有低于当前油价的,则在满油能到达的范围内找出最低的油价加油站,并且在本站加满油,去往下一站
			int k=-1;//最低油价的加油站编号
			double priceMin=INF;//最低油价
			for(int i=now+1;i<=n&&st[i].dis-st[now].dis<=MAX;i++){
				if(st[i].price<priceMin){
					priceMin=st[i].price;
					k=i;
					//如果找到第一个比当前油价还低的,直接break
					if(priceMin<st[now].price){
						break;
					} 
				}
			}
			if(k==-1) break;//满油状态无法到达加油站,退出循环输出结果
			//下面为能找到可达的加油站,计算转移花费
			double need=(st[k].dis-st[now].dis)/Davg;//从now 转移到k需要的油量 
			if(priceMin<st[now].price){//如果加油站k的油价低于当前油价 
				 if(nowTank<need){//尤其注意,这里也是要判断的,而我自己忘记判断了 
				 	ans+=(need-nowTank)*st[now].price;
				 	nowTank=0;//到达加油站k后油箱为0 
				 }
				 else{//如果当前油量超过need 
				 	nowTank=-need;//直接到达加油站,不需要计算钱了 
				 } 
			}
			else{//如果加油站k的油价高于当前油价
				ans+=(Cmax-nowTank)*st[now].price;//要足够严谨,此时也许油箱里有油 
				nowTank=Cmax-need;//到达k站后油量为Cmax-need 
			}
			now=k; 
		}
		if(now==n){//说明是循环结束退出,能够到达重点 
			printf("%.2f",ans); 
		}
		else{
			printf("The maximum travel distance = %.2f\n",st[now].dis+MAX);
		} 
	}
	return 0;
} 



我自己写的,对照一下,差别写在上面的解法的最上方注释

//注意这一题等于号两边是有空格的 
//pat的题目一定要保证精确度!,精确度不够就是答案错误! 
//int r=0,而不是int r.这个小小的地方一改就大部分分数得到了 
//这一题我用%lf格式符输入float型的数据,结果居然赋值进去的是0,所以请严格使用控制字符.但是双精度的输出依然用%f.输入必须用%lf 
//这一题我花不到一个小时还是写完了的 
//最好设置终点为油价为0的加油站,想想为什么 
	/*算法分析:
	(1)寻找距离当前加油站最近的,且油价低于当前油价的加油站(k),在当前加油站加好能够到达k的油,然后开到k站,循环加油
	(2)如果找不到油价低于当前加油站的加油站,找到油价较低的加油站,在本站加满油,然后到k站 
	 (3)如果在满油的状态下到达不了最近的加油站,则用当前加油站的距离+满油行使的距离,就是最大行使距离,退出循环
	 (4)上面的策略在满足条件3或者行使距离到达目的地时结束。 
	*/
//从杭州到别的地方,是这个意思。关关说反正用double不会错 。如果程序返回1说明是陷入了死循环了 
//C,油箱的最大容量。D杭从州到该城市的距离。Davg每升油可以行使的距离。N加油站总数
//Pi单元油价,D这个站到杭州的距离。一开始油箱是空的。结果打印一路上最便宜的价格。如果到不了目的地,打印最大行驶距离。2位小数
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LOCAL 
using namespace std;
 
struct GasStation{
	double price;
	double distance;
}st[510]; 
bool cmp(GasStation a,GasStation b){
	return a.distance<b.distance;
}
double nowtank=0.0;//当前油箱油量 
int main(){
	#ifdef LOCAL
	freopen("A1033data.in","r",stdin);
	freopen("A1033data.out","w",stdout);
	#endif
	//int tank,Pat还是相当严谨的,如果不说明数据情况,就要用double或者float
	int n;//一共的加油站数 
	double tank,D,per;
	scanf("%lf%lf%lf%d",&tank,&D,&per,&n);
	for(int i=0;i<n;i++){
		scanf("%lf",&st[i].price);
		scanf("%lf",&st[i].distance);
		//printf("%lf\n",st[i].distance);
	}//数据全部输入了 
	sort(st,st+n,cmp);//按照离杭州距离从小到大排序
	if(st[0].distance!=0){
		printf("The maximum travel distance = 0.00\n");//因为起点处不能没有加油站,没有就是最远距离0.00
		return 0; 
	}
	st[n].distance=D;
	st[n].price=0.0;//设置0是为了第一个策略,寻找最近且价格最低的油,加满能够到达那个加油站的油即可。我们只要加满到达终点的油就行了 
	/*算法见上面*/ 
	double ans=0.0;//路程.ans不需要每次累计的 
	double money=0.0; //总钱数 
	double tankleft=0.0;//油箱剩余油量 
	int i=0;//现在是第0个加油站 
	//必须要计算满油时能行使多远
	double tankD=tank*per;//满箱油行使的距离 
	while(i<n){//一开始写的D-ans>1e-6 
		//当汽车还没有到达重点,关于到不了等等,会用break。如果到达终点站,则D==ans,考虑到小数,就是D-ans<1e-6 
		//是否需要保留当前的i,下次可以从i开始遍历,恩是要这样的。这样可以省时间
		//因为这里已经把终点站设为最后一个价格为0,距离为D的站 
		GasStation right;
		int r=0; //这里一开始没有写int r=0,直接写的 int r .加个i=0,所有能走完的case就都对了! 
		for(int j=i+1;j<=n;j++){//从第一个到第n+1个了 
			//从i到油箱能满的情况
			if((st[j].distance-st[i].distance)>tankD){
				right=st[j-1];//这最后一个j多一个的就是右边界.注意肯定都是在满箱有可到达的情况下的 
				r=j-1;
				break;
			} 
		}
		if(r==i){
			//说明即使加满油,也到不了任何一个加油站
			//ans+=tankD;
			ans=st[i].distance+tankD; 
			printf("The maximum travel distance = %.2lf\n",ans);
			return 0;
		}
		double minprice=st[i+1].price;//设置离它最近的一个为最小油价处 
		int mindex=i+1;
		for(int j=i+1;j<=r;j++){
			if(st[j].price<minprice){
				minprice=st[j].price;
				mindex=j;
			}
		}
		//printf("%d %d\n",mindex,i);
		//printf("%d",j);
		double dd=st[mindex].distance-st[i].distance;
		double need=(st[mindex].distance-st[i].distance)/per;
		//printf("%lf\n",dd);
		if(minprice<st[i].price){
			money+=st[i].price*(need-tankleft);//每升油的价格*走这么远路需要的油箱升数(一共多远,每箱油走多远) 
			ans+=dd;
			tankleft=0.0;
			//printf("%.2lf",ans);
		}
		else{
			//要注意,现在从i+1到right范围内都是汽车加满油可以到达的地方。现在的情况是,周围没有一家比当前这家更便宜,所以要加满油 
			money+=st[i].price*(tank-tankleft);
			ans+=dd;
			tankleft=tank-need;//油箱剩余油等于满油减去走着一路用去的油。 
		}
		i=mindex;//把下一个i赋值为价格最低的下一个加油站 
	}
	printf("%.2lf\n",money);
	return 0;
} 


阅读更多
文章标签: PAT c++ 算法
个人分类: PAT
上一篇PAT B1020或者A1070 月饼注意设置看清数据类型
下一篇PAT A1037 Magic Coupon 记得把0剔除哦
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭