这题和上一题相似,都是选出当前最佳步数,但策略要更加复杂。
我这里把加油站分成了两类:
第一类继承者:价钱比当前油价钱便宜或相等,离得最近。
第二类继承者:无第一类继承者的情况下,剩下的油都比第一类贵,从贵的中找出一个相对便宜的。
贪心策略:
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;
}