【题解】旅行家的预算(贪心)

八中OJ

洛谷

这题太复杂了,能否全A看数据。。。
很好的一道模拟贪心题

算法原理(优先级)如下:

1.枚举途中经过的加油站,每经过一个加油站,计算一次花费

2.在一个加油站所需要加的油,就是能够支持它到达下一个油价比它低的加油站的量;

3.如果在这个加油站即使加满油,都不能到达一个比它油价低的加油站,(1)就把油箱加满,前往能够到达的加油站中油价最低的那个;(2)或者直接到终点;

4.如果在这个加油站即使加满油,都不能到达任意一个加油站,也不能到达终点城市,说明无解;

  • 先考虑2再考虑3,2一定划算,且无后续性

  • 第二点:注意不仅要省钱,还要是最近的加油站(尽早省钱美滋滋)

  • 第三点:前提是不省钱,注意要考虑直接到终点的情形

  • 第三点:为什么要加满油?因为这样可以减少在下一个加油站(价格更贵)所需要加的油量。

贪心思路就是这样,能否实现看本事

first try : 60

#include<cstdio> 
#include<cstring>
#include<algorithm>
using namespace std;
double d1,c,d2,n,p1,lc,ans;
struct liu{
	double d,p,h;
}a[105];
int main() {
	scanf("%lf%lf%lf%lf%lf",&d1,&c,&d2,&p1,&n);
	lc=c*d2;
	for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i].h,&a[i].d,&a[i].p);
	double i=0,yq=p1;
	while(i<d1) {
		double t=i+lc,_min=1e9;
		int bh=0;
		for(int j=1;j<=n;j++) {
			if(a[j].d>i&&a[j].d<=t&&a[j].p<_min&&a[j].d<d1) _min=a[j].p,bh=j;
		}
		if(bh==0) {
			if(t>=d1) {
				ans+=(d1-i)*yq/d2;
				break;
			}
			else {
				printf("No solution");
				return 0;
			}
		}
		else {
			if(t>=d1) {
				if(yq<=_min) {
					ans+=(d1-i)*yq/d2;
				    break;
				}
			}
			ans+=(a[bh].d-i)*yq/d2,i=a[bh].d,yq=a[bh].p;
		}
	}
	printf("%.2lf",ans);
}
}

错因:

1.未考虑是否省钱

2.不是选的最近的油站,而是选最便宜的

3.未考虑剩余油

样例输入:
475.6 11.9 27.4 14.98 6
102.0 9.99
220.0 13.29
256.3 14.79
275.0 10.29
277.6 11.29
381.8 10.09


样例输出:
192.15


真实输出:
192.32

于是我权衡了网上思路,进行第二次尝试

正解:

second try : 100

#include<cstdio> 
#include<algorithm>
#include<cstring>
using namespace std;
double d1,c,d2,n,p1,lc,ans,yx;
struct liu{
	double d,p;
}a[10005];
int main() {
	scanf("%lf%lf%lf%lf%lf",&d1,&c,&d2,&p1,&n);
	lc=c*d2;
	for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].d,&a[i].p);
	double i=0,yq=p1;
	while(i<d1) {
		double t=i+lc,_min=1e9;
		int bh=0;
		for(int j=1;j<=n;j++) {//在范围内寻找能省钱且最近的 
			if(a[j].d>i&&a[j].d<=t&&a[j].d<d1&&a[j].p<yq&&a[j].d<_min) {
			    bh=j,_min=a[j].d;
			} 
		} 
		if(bh!=0) ans+=((a[bh].d-i)*yq-yx)/d2,i=a[bh].d,yq=a[bh].p,yx=0;
		//剩余油不可能直接使到达 
		
		//不能找到,分为能否直接到达终点以及有无后续加油站两方面同时考虑 
		else {
			_min=1e9,bh=0;
			for(int j=1;j<=n;j++) {//在范围内寻找最便宜(并不省钱)的加油站 
			    if(a[j].d>i&&a[j].d<=t&&a[j].d<d1&&a[j].p<_min) _min=a[j].p,bh=j;
		    }
		    //无后续加油站且无法直接到达终点 
		    if(bh==0&&t<d1) {
		        printf("No Solution");
				return 0;
			}
			//能直接到达,最划算 
			if(t>=d1) {
				if(yx<(d1-i)/d2) {
					ans+=((d1-i)/d2-yx)*yq;
				}
				break;
			}
			
			//不能直接到达但有后续加油站,先加满(省钱),记录剩余油的多少
			//加满和到最便宜的地方是关键 
			else {
				ans+=(c-yx)*yq;
			    yx=c-(a[bh].d-i)/d2;
			    yq=a[bh].p,i=a[bh].d;
			}
		}
	}
	printf("%.2lf",ans);
}

写得算完整了,欢迎打脸质疑我

仔细品味两次找油站!第一次是省钱且最近,第二次只是最便宜

(完)

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值