1033 To Fill or Not to Fill (25 分)

如需查看最终代码直接看通过代码题目下的代码段。

原题

With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time. Different gas station may give different price. You are asked to carefully design the cheapest route to go.

Input Specification:

Each input file contains one test case. For each case, the first line contains 4 positive numbers: Cmax​ (≤ 100), the maximum capacity of the tank; D (≤30000), the distance between Hangzhou and the destination city; Davg​ (≤20), the average distance per unit gas that the car can run; and N (≤ 500), the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: Pi​, the unit gas price, and Di​ (≤D), the distance between this station and Hangzhou, for i=1,⋯,N. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the cheapest price in a line, accurate up to 2 decimal places. It is assumed that the tank is empty at the beginning. If it is impossible to reach the destination, print The maximum travel distance = X where X is the maximum possible distance the car can run, accurate up to 2 decimal places.

Sample Input 1:

50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300

结尾无空行

Sample Output 1:

749.17

结尾无空行

Sample Input 2:

50 1300 12 2
7.10 0
7.00 600

Sample Output 2:

The maximum travel distance = 1200.00

思路 

这道题的思路是在在油价便宜的站加尽可能多的油,油价贵的站加尽可能少的油,具体操作是:每个到达的站判断一次,如果这个站能抵达的范围内有更便宜的站,就保证能到那个站就行,如果没有(也就是说这个站就是最便宜的),就把油加满,然后在范围内选一个第二便宜的站补充油量扩大能到的范围。

通过代码

//水箱最多装v,距离目的地skm,一个单位的气体汽车可以走perskm远,一共n个站
//每个站气体价格是p[i],距离杭州x[i]
#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
#define Equ(a,b) ((fabs((a)-(b)))<eps)
#define MoreEqu(a,b) (((a)-(b))>-eps)
#define More(a,b) (((a)-(b))>eps)
struct node{
    double p,x;
}nod[501];
bool cmp(node a, node b)
{
    return a.x < b.x;//将加油站照位置升序排列
}
int main() {
	double v, s, pers, price = 0, dis = 0, oil = 0, needoil;
	int n;//n是一共多少个站
	//v是水箱容积,s是两站路程,pers是一单位油能走多远
	cin >> v >> s >> pers >> n;
	for (int i = 0; i <= n - 1; i++) {
		cin >> nod[i].p >> nod[i].x;
		getchar();
	}
	sort(nod, nod + n, cmp);
	if (nod[0].x != 0 || n <= 0) {
		printf("The maximum travel distance = 0.00");
		return 0;
	}
	nod[n].p = 0;
	nod[n].x = s;
	double max = v * pers;//一次能走的最远距离
	int i = 0;
	int j = 1;
	int min = j;
	while (true) {
		if (j > n) {
			printf("%.2f", price);
			return 0;
		}
		if (More((nod[j].x - nod[i].x), max)) {
			printf("The maximum travel distance = %.2f", (dis + max));
			return 0;
		}
		while (More(max, (nod[j].x - nod[i].x)) && j <= n) {
			if (More(nod[i].p, nod[j].p)) {
				min = j;
				break;
			}
			else if (More(nod[min].p, nod[j].p)) {
				min = j;
			}
			j++;
		}
		j--;
		needoil = (nod[min].x - nod[i].x) / pers;
		dis = nod[min].x;
		if (More(nod[i].p, nod[min].p)) {
			if (MoreEqu(needoil, oil)) {
				price += (needoil - oil)*nod[i].p;
                oil=0;
			}

		}
		else {
			price += (v - oil) * nod[i].p;//油加满
			oil = v - needoil;
		}
		i = min;
		j = i + 1;
		min = j;
	}
	return 0;
}

 总结

方法

  1. 一开始想的是在整段路上选择最便宜的点,在该点加尽可能多的油,尽可能多指的是加满和加到能到终点两者中满足一项,然后在这个最便宜的点的两侧又来选择最便宜的点重复该操作,这样就可以用递归解决。这个想法饶了我很久还是只能部分正确(22/25),放在这里以后有空再来理解吧。(最绕的就是start究竟取多少,由下面的代码可知,在频繁地执行start+1-1操作)。由此可见,考场上尽量不要用递归,你想不清楚的小老弟wuwu~
    //水箱最多装v,距离目的地skm,一个单位的气体汽车可以走perskm远,一共n个站
    //每个站气体价格是p[i],距离杭州x[i]
    #include<bits/stdc++.h>
    using namespace std;
    const double eps = 1e-8;
    #define Equ(a,b) ((fabs((a)-(b)))<eps)
    #define MoreEqu(a,b) (((a)-(b))>-eps)
    #define More(a,b) (((a)-(b))>eps)
    struct node{
        double p,x;
    }nod[501];
    bool cmp(node a, node b)
    {
        return a.x < b.x;//将加油站照位置升序排列
    }
    double v, s, pers, dis = 0, oil = 0, needoil;
    double price = 0;
    int n;//n是一共多少个站
    //v是水箱容积,s是两站路程,pers是一单位油能走多远
    int canornot=1;
    int findprice(int start, int end, double oil) {
    	double max = v * pers;
    	double nodoil0, nodoil1;
    	int per;
    	if (start != 0) {
    		start++;
    	}
    	int min = start;
    	for (int i = start; i < end; i++) {
    		if (nod[min].p > nod[i].p) {
    			min = i;//找到最小
    		}
    	}
    	if (start != 0) {
    		per = start-1;
    	}
    	else {
    		per = start;
    	}
    	if (nod[min].x - nod[per].x < max && nod[min].p>nod[per].p) {
    		nodoil0 = oil - (nod[min].x - nod[per].x) / pers;
    	}
    	else {
    		nodoil0 = 0;
    	}
    	if (nod[end].x - nod[min].x < max) {
    		nodoil1 = (nod[end].x - nod[min].x) / pers;
    	}
    	else {
    		nodoil1 = v;
    	}
    	price += (nodoil1 - nodoil0)*nod[min].p;
    	if (min - start >= 1) {
    		findprice(start, min, 0);
    	}
    	if (end - min > 1 && nod[end].x - nod[min].x > max) {
    		findprice(min, end, nodoil1);
    	}
    	else if (nod[end].x - nod[min].x > max) {
    		printf("The maximum travel distance = %.2f", (nod[min].x + max));
    		canornot = 0;
    	}
    	return price;
    }
    int main() {
    	cin >> v >> s >> pers >> n;
    	for (int i = 0; i <= n - 1; i++) {
    		cin >> nod[i].p >> nod[i].x;
    		getchar();
    	}
    	sort(nod, nod + n, cmp);
    	nod[n].p = 999;
    	nod[n].x = s;
    	findprice(0, n, 0);
    	if (canornot) {
    		printf("%.2f", price);
    	}
    	
    }
  2. 然后来看一下某大佬的神仙思路,他是把路程存为数组,每次更新单位路程的最短价格,代码量少还好理解: https://blog.csdn.net/wangxianhualian/article/details/98976642

知识 

  1. 如果记不得该引入什么库就:
    #include<bits/stdc++.h>

    这里面包括了很多常用的库,一定要记下来,不多只能在拼题a上用,vs不行。

  2.  
    #include <algorithm>
    bool cmp(node a, node b)
    {
        return a.x < b.x;//将加油站照位置升序排列
    }
    int main(){
        sort(nod, nod + n, cmp);
        return 0;
    }

    这次用sort给struct node类型的结构排除,结果自定义了cmp却忘了写上,报的错又多又看不懂。

心态 

确实有点搞伤了这道题,以后记得先在草稿纸上用伪代码演算清楚再写代码,另外如果考试遇到这样的题一直不能全对就先放下来做别的,不要为一道题把脑子搞浆糊了。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值