牛客oj 习题7.2 To Fill or Not to Fill(经典贪心)

这题和上一题相似,都是选出当前最佳步数,但策略要更加复杂。

我这里把加油站分成了两类:

第一类继承者:价钱比当前油价钱便宜或相等,离得最近。
第二类继承者:无第一类继承者的情况下,剩下的油都比第一类贵,从贵的中找出一个相对便宜的。


贪心策略:
1.先把所有加油站按距离排个序。
2.从中找出第一类继承者和第二类继承者(若无第一类)。
3.如果无第一类继承者且安全范围内到达终点,直接加上到终点距离的油即可。
4.如果找到第一类继承者,加上到第一类继承者加油站之间距离的油量,注意原本也可能还有剩余的油。
5.如果未找到第一类继承者,但找到了第二类继承者,则先加满油后扣除到该加油站距离的油量。
6.如果两类继承者都没有找到,直接加上到能到达最远点的油即可。

注意这题同一个地点可能有多个加油站,通常用两种方法解决:对相同地点的加油站费用由低到高排序再做相应处理;直接在输入时去重。因为后一种可以节省时间,所以就使用了后一种。不过我写复杂了,用map会大大简化,可惜意识到这个问题时候已经写完了,就这样将就一下了。

PS:这题昨天写的,写了我大半天,刚开始贪心策略倒是对了,但就是模拟不出来。变量太多,边界也很多,写了一遍后写的又臭又长控制不住了,想放弃。后来看了别人题解我策略没问题就不想浪费,索性干脆删了重写了一遍,因为边界又各种卡不过好在牛客提供样例(这方面的确牛客比其他oj好),总算是过了。事实表明贪心尽量找出最好写的方法不然能写崩,我果然在贪心这方面还是太菜了。。。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
#include <cctype>
#include <cmath>
#include <climits>
 
using namespace std;
 
const int MAXN = 50005;
const int INF = INT_MAX;

struct Station{
	double distance;
	double price;
}; 

bool cmp(Station x, Station y){
	return (x.distance < y.distance);
}

int main(){
  //  freopen("in.txt", "r", stdin);
    double Cmax, D, Davg;
    int N;
    double judge[MAXN];
    while(~scanf("%lf %lf %lf %d", &Cmax, &D, &Davg, &N)){
    	memset(judge, 0, sizeof(judge));
    	int repeat = 0;
    	Station station[N+5];
    	double x, y;
    	int real = 0;
    	for(int i = 0; i < N; i++){
    		scanf("%lf %lf", &x, &y);
    		if(judge[(int)y] != 0){//价钱不为0 
    			repeat++;
    			int pos;
    			for(int j = 0; j < real; j++){
    				if(station[j].distance == y){
    					pos = j;
    					break;
    				}
    			}
    			if(x < station[pos].price) station[pos].price = x;
    			continue;
    		}
    		station[real].price = x;
    		station[real].distance = y;
    		judge[(int)y] = x;
    		real++;
    	}
    	N -= repeat;
    	sort(station, station+N, cmp);
    	int cur = 0;//未经过的加油站编号及替身 
    	double oil = 0;//当前油量 
    	double start = 0, end = D;//起点、终点 
    	double ansprice = 0;//最终所费价格 
    	bool flag = true, flag1, flag2;
    	while(start != end){
    		//找出第一类和第二类继承者 
    		int safedis = station[cur].distance + Cmax * Davg;
    		flag1 = false, flag2 = false;
    		int next;
    		double minprice = INF;
    		for(int i = cur+1; (station[i].distance <= safedis) && (i < N); i++){
    			if((!flag1) && (station[i].price <= station[cur].price)){
    				flag1 = true;
    				next = i;
    				break;
    			}
    			else if(station[i].price > station[cur].price && ((station[cur].distance + Cmax * Davg) < D)){
    				if(station[i].price < minprice){
    					flag2 = true;
    					minprice = station[i].price;
    					next = i;
    				}
    			}
    		}
    		//分情况处理 
    		if((!flag1) && (!flag2) && ((station[cur].distance + Cmax * Davg) >= D)){//到终点 
    			ansprice += ((D - station[cur].distance)/Davg - oil)*station[cur].price;
    			start = end;
    		} 
    		else if(flag1){//第一类继承者 
    			ansprice += ((station[next].distance - station[cur].distance)/Davg - oil)*station[cur].price;
    			start = station[next].distance;
    			oil = 0;
    			cur = next;
    		}
    		else if(flag2){
    			ansprice += ((Cmax - oil)*station[cur].price);
    			start = station[next].distance;
    			oil = Cmax - (station[next].distance - station[cur].distance)/Davg;
    			cur = next;
    		}
    		else{//到不了终点 
    			printf("The maximum travel distance = %.2lf\n", start + Cmax * Davg);
    			flag = false;
    			start = end;
    		}
    	}
    	if(flag){
    		printf("%.2lf\n", ansprice);
    	}
    }
    return 0;
}
发布了411 篇原创文章 · 获赞 72 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/Flynn_curry/article/details/104803964