(PAT甲级)1033 To Fill or Not to Fill

1033 To Fill or Not to Fill

是决策,不太确定能不能用贪心。一开始自己没想清楚,参考了别人的思路,发现还是贪心。

实际上就是两个规则

  • 在可到达的最大范围内,存在相邻的加油站比你现在所处的加油站便宜,那么加油量恰好能让车到达这个新加油站,是一个局部最优决策。
  • 如果可达最大范围内没有更便宜的新加油站,就加满油。这样做使你到了新的加油站也能用剩余的便宜油多走一会,降低成本。

注意特判起点没有加油站,输出

The maximum travel distance = 0.00

感觉别人的代码看着不是很清爽,自己写了一下,或许看着更直观点

#include<bits/stdc++.h>
using namespace std;
struct Station{
	double p;
	int d;
}s[505];
int c,d,dv,n;
double sum = 0;
const double INF = DBL_MAX;
bool cmp(Station a,Station b){//同距离,费用小在前
	if(a.d==b.d)
		return a.p<b.p;
	return a.d<b.d;
}
int main(){
	cin>>c>>d>>dv>>n;
	for(int i=0;i<n;i++){
		cin>>s[i].p>>s[i].d;
	}
	sort(s,s+n,cmp);
	if(s[0].d!=0){//特判起点没有加油站
		cout<<"The maximum travel distance = 0.00"<<endl;//注意输出不是0而是0.00 (一般认为是0)
		return 0;
	}
	int posNow=0;//当前位置
	int dRes=0;//可走距离
	int dMax = c*dv;//最大行程
	double pNow = s[0].p;//当前油价
	while(posNow<d){
//		printf("posNow %d pNow %f dRes %d\n",posNow,pNow,dRes);
		int posNext=-1;
		double pMin=INF;
		bool flag=false;//没找到低价点
		for(int i=0;i<n&&s[i].d<=posNow+dMax;i++){//假设终点后没有加油站
			if(s[i].d<posNow)continue;
			if(s[i].p<pNow){//找到低价点,不用多加更新
				if(dRes>=s[i].d-posNow){//剩够
					dRes-=s[i].d-posNow;
				}
				else if(dRes){//有剩
					sum+=pNow*(s[i].d-posNow-dRes);
					dRes=0;
				}
				else
					sum+=pNow*(s[i].d-posNow);
				posNow = s[i].d;
				pNow = s[i].p;
				flag = true;
				break;
			}
			if(s[i].p<pMin&&posNow<s[i].d){//下一个最便宜点,不含posNow
				pMin=s[i].p;
				posNext = i;
			}
		}
		if(!flag){//加满油箱,去下一站
			if(posNow+dMax>=d){//能到终点
				sum+=pNow*(d-posNow);
				printf("%.2f\n",sum/dv);
				break;
			}
			else if(posNext==-1){//没有站
				printf("The maximum travel distance = %.2f\n",(double)(posNow+dMax));
				break;
			}
			else{
				sum+=pNow*(dMax-dRes);//加满油箱
				dRes = dMax-(s[posNext].d-posNow);//到下一站后的剩余距离
				posNow = s[posNext].d;
				pNow = s[posNext].p;
//				printf("ADD posNow %d pNow %f dRes %d\n",posNow,pNow,dRes);
			}
		}
	}
	return 0;
}

启示

1、写贪心题的关键在于确定贪心策略,策略定好后才好实现。不然硬模拟很容易写不出来。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值