贪心—To Fill or Not to fill

0x00 题目地址

To Fill or Not to Fill__牛客网 (nowcoder.com)

0x01 分析

符合最优子结构、无后效性、重复子问题三个条件,因此可以使用贪心求解。 

先按照距离排序,将加油站排成一条线。

算法每一步的思路:

        1.首先判断油箱加满时的最大里程能否支撑到下一个加油站。(只需判断相邻的油站距离是否大于加满油的最大里程即可,不满足的话就可以输出最大路程,然后return 0)

        2.其次,寻找(current_location,current_location+最大里程]内油价最便宜的加油站

        2.1 若这个最便宜的油价甚至比当前加油站的更便宜,则只需确保油箱的油足够到下一站即可。

                2.1.1 可能油箱本来油量就够,那就不需要加        

                2.1.2 若油箱的油量不够,那么就加到足够到该加油站的油量即可,不需要多加。

        2.2 若这个最便宜的油价比当前加油站的还要贵。那么就在当前的加油站加满油。

最终判断路程是否==距离。然后打印输出总花费即可。

0x02 完整代码

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct station {
	double price;
	double dis;
};

bool compare(station A, station B) {
	if (A.dis == B.dis) {
		return A.price < B.price;
	}
	return A.dis < B.dis;
}


int main() {
	double cmax, d, davg, n;
	while (cin >> cmax >> d >> davg >> n) {
		vector<station> station(n + 1);
		for (int i = 0; i < n; ++i)
		{
			cin >> station[i].price >> station[i].dis;
		}
		//将终点也作为加油站
		station[n].price = 0;			//将终点站也看成加油站
		station[n].dis = d;
		sort(station.begin(), station.end(), compare);

		double maxrun = cmax * davg;  //最大里程
		double run = 0;       //路程
		double cost = 0;		//总花费
		double fuel = 0;      //当前油箱的油量

		for (int i = 0; i < n; i++) {
			if ((station[i + 1].dis - station[i].dis )> maxrun) {
				printf("The maximum travel distance = %.2f\n", run + maxrun);
				return 0;
			}

			//寻找可行使区间内最便宜的加油站
			double cheapest = i+1;
			//寻找比当前的加油站油价还便宜的加油站
			double nearest = i+1;
			for (int j = i + 1; j < n + 1 && station[i].dis + maxrun >= station[j].dis; j++) {
				if (station[cheapest].price >= station[j].price) {
					cheapest = j;
				}

				if (station[j].price <= station[i].price) {
					nearest = j;
					break;
				}
			}

			if (station[cheapest].price > station[i].price) { //当前的油价比后面区间内的油价都便宜,则直接加满
				cost += station[i].price * (cmax- fuel);
				fuel = cmax;
				run += station[cheapest].dis - station[i].dis;
				fuel -= (station[cheapest].dis - station[i].dis) / davg; //减去到下一个加油站的油耗
				i = cheapest - 1; //要-1,因为for循环还有个i++
			}
			else { //油价比当前的站还便宜,只需加够足够支撑到下一加油站的油量即可
				//看看剩余的油箱是否能跑到那个站
				if (fuel < (station[nearest].dis - station[i].dis) / davg) { //如果跑不到下一个站,那就加适量的油
					cost += station[i].price * ((station[nearest].dis - station[i].dis) / davg - fuel);

					fuel = (station[nearest].dis - station[i].dis) / davg;
				}
				
				fuel -= (station[nearest].dis - station[i].dis) / davg; //减去到下一个加油站的油耗
				run += station[nearest].dis - station[i].dis;
				i = nearest - 1;
			}

		}

		if (run == d) {
			printf("%.2f\n", cost);
		}

	}
	return 0;
}

### 牛客网中与贪心算法相关的试题 #### BM95 分糖果问题 此题的核心在于通过排序后,选择局部最优解来实现全局最优。具体做法是先对数组进行升序排序,然后从右向左依次选取第 \(3n-2\)、\(3n-4\) 等位置的元素[^1]。代码如下: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int n = 0; cin >> n; vector<int> v(3 * n); for (int j = 0; j < 3 * n; j++) { cin >> v[j]; } sort(v.begin(), v.end()); long long num = 0; int beg = 3 * n - 2; while (n--) { num += v[beg]; beg -= 2; } cout << num << endl; return 0; } ``` #### BM96 主持人调度(二) 该题同样使用了贪心算法的思想,目的是在满足题目条件的前提下,尽量选取局部最优解以实现全局最优解[^1]。 #### 腾讯笔试题:贪吃的小Q 此题要求计算小Q第一天最多能吃多少块巧克力,同时保证每天吃的巧克力数量不少于前一天的一半。解题思路采用二分查找的方法[^3]。以下是Python代码实现: ```python # -*- coding:utf-8 -*- n, m = [int(i) for i in input().split()] def my_sum(s): total_sum = 0 for i in range(n): total_sum += s s = (s + 1) // 2 return total_sum low, high = 1, m while low <= high: mid = (low + high) // 2 if my_sum(mid) == m: print(mid) break elif my_sum(mid) < m: low = mid + 1 else: high = mid - 1 if low > high: print(low - 1) ``` #### To Fill or Not to Fill【区间贪心】 此题涉及加油策略的选择,目标是最小化总花费。通过遍历加油站并计算所需油量和费用,可以得出最优解[^4]。部分代码如下: ```cpp for (int i = 0; i < n; i++) { tmp = (a[i].di + max < d ? max : d - a[i].di); cnt = 0; for (int j = a[i].di; j < a[i].di + tmp; j++) { if (flag[j] == 0) { flag[j] = 1; cnt++; } } sum += cnt / (davg * 1.0) * a[i].pi; } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ad_m1n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值