PAT To Fill or Not to Fill

5 篇文章 0 订阅
链接: https://www.nowcoder.com/questionTerminal/4ad3d8cde8ca4889a32ed0a89edeefeb
来源:牛客网

[编程题]To Fill or Not to Fill (25)
With highways available, driving a car from Hangzhou to any other cityis easy. But since the tank capacity of a car is limited, we have tofind gas stations on the way from time to time. Different gas stationmay give different price. You are asked to carefully design thecheapest route to go.
输入描述:
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.


输出描述:
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.
示例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

输出

749.17
//#include"stdafx.h"
#include"stdio.h"
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<vector>
#include<deque>
#include<math.h>
using namespace std;
double cmax,dis;
int n;
double per;
struct node{
	double p;
	double d;
	node(double p,double d):p(p),d(d){}
};
vector<node>vec;
double ans=0;
double price,d;


bool cmp(node a,node b){return a.d<b.d;
}


void cal(int in,double tank){//tank refer to how much gasoline remaining;


	double cm=min(1.0*cmax,(dis-vec[in].d)/per);//maybe it's not necceessary to fill your tank,because the //destination is not so far;
	double far=cmax*per;//if full,the farest distance to go
	if((in+1<vec.size()&&vec[in+1].d-vec[in].d>far)||in+1>=vec.size()){if(vec[in].d+far<dis){
//when you can not reach the destination,maybe because there is no next station or the next sation is beyond the //farest 

		cout<<"The maximum travel distance = ";
		printf("%.2f",vec[in].d+far);
	}
	else {
		ans+=((dis-vec[in].d)/per-tank)*vec[in].p;
		printf("%.2f\n",ans);}


	}


	else {int i,flag=0;double minp=vec[in+1].p,sel=in+1;
	for(i=in+1;i<vec.size()&&vec[i].d<=vec[in].d+far;i++)
	{if(vec[in].p>=vec[i].p){ans+=vec[in].p*((vec[i].d-vec[in].d)/per-tank);
		cal(i,0);flag=1;break;//if there is an accessable station whose price is lower than the current //one's
	}
	if(minp>vec[i].p){sel=i;minp=vec[i].p;}//at the same time,make notes of the station with the lowest price
	}
	if(flag==0){


		ans+=vec[in].p*(cm-tank);//if all the available stations offer gasoline at a price higher,try to //get to the lowest one
		cal(sel,cm-(vec[sel].d-vec[in].d)/per);//fill as possible as you can
	}	}}


int main(){
	// freopen("c://jin.txt","r",stdin);
	cin>>cmax>>dis>>per>>n;
	while(n--){
		cin>>price>>d;
		vec.push_back(node(price,d));
	}
	sort(vec.begin(),vec.end(),cmp);
	cal(0,0);
	//freopen("CON","r",stdin);
	// system("pause");


	return 0;
}
2018.3.7重刷了这道题,再次总结一下思路  

需要的注意的地方

1.对加油站按距离排序

2.相同位置的加油站可能有多个,注意去掉重复,保留相同位置价格最低的加油站,将有利于计算

3.计算相邻加油站的之间的距离,如果超过满油箱能行驶的范围,一定达不到终点

4.在顺序枚举加油站时,采用贪心算法

如果下一站的油比这一站的便宜,油箱里只需要够到达下一站的油

否则,油箱里应该存够到最近的更便宜的加油站所需要的油,并开往下一站。

在这里有可能后面没有更便宜的加油站了,并且终点站在满油箱的距离内,那就加到够终点站的油,否则,在这一站加满油

如果在满油箱距离内都没有更便宜的加油站了,那就加满油


//#include "stdafx.h"
#include"stdio.h"
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=550;
const int inf=0x7fffffff;
 
double cmax,dis,g;
int n;
double l;
double p,d;
struct node{
    double p;
    double d;
    double f;
	node(double p,double d):p(p),d(d){}
};
vector<node>no;
double dp[maxn];
string s="The maximum travel distance = ";
bool cmp(node a,node b)
{
   if(a.d!=b.d) return a.d<b.d;
    else return a.p<b.p;
}
 
 
 
 
 
 
int main(){
 
 
 
    //freopen("c://jin.txt","r",stdin);
    while(cin>>cmax>>dis>>g){
        int flag=0;
        double far=0;
        cin>>n;
        l=cmax*g;
        for(int i=0;i<n;i++)
        {cin>>p>>d;
		no.push_back(node(p,d));
		}
		sort(no.begin(),no.end(),cmp);
        for(int i=1;i<n;i++)
			if(no[i].d==no[i-1].d){no.erase(no.begin()+i);n--;}
		
		for(int i=0;i<n;i++)
		{if(i!=n-1){no[i].f=no[i+1].d-no[i].d;
	
		}
        else no[n-1].f=dis-no[n-1].d;
        if(no[i].f>l){flag=1;far=no[i].d+l;break;}
        }
        if(flag){cout<<s;printf("%.2f\n",far);}//前面都在计算两站间的距离是否超过加满油行驶的范围
        else{
 
                int i=0;double ans=0;//i表示现在到了哪一个加油站,ans表示当前花费的钱
                double w=0,need;//w表示当前剩下多少油,need表示现在需要加多少油
                while(i<n){
				if(i==n-1){ans+=max(((dis-no[i].d)/g-w)*no[i].p,0.0);break;}//如果已经是最后一站了,只需要够到终点的油
			        else if(no[i+1].p<=no[i].p){//如果下一站便宜
				        need=no[i].f/g;
					if(w>=need){w-=need;}
					else{ans+=(need-w)*no[i].p;w=0;}
					i++;
                            }
              
				else{ int j=1;
				while(i+j<n&&no[i+j].d-no[i].d<=l&&no[i+j].p>no[i].p)j++;
				if(i+j==n){//如果后面没有更便宜的了
					if(dis-no[i].d<=l){ans+=max(((dis-no[i].d)/g-w)*no[i].p,0.0);break;}
					else {ans+=(cmax-w)*no[i].p;
					i++;
					w=cmax-no[i].f/g;}
				}
				else if(no[i+j].d-no[i].d>l){//如果在最大距离内没有更便宜的了
				        ans+=(cmax-w)*no[i].p;
					w=cmax-no[i].f/g;
					i++;
				
				}
				else{//i+j号加油站是比i号更便宜
					need=(no[i+j].d-no[i].d)/g;
				        if(w<need){ans+=(need-w)*no[i].p;w=need;}
     				        w-=no[i].f/g;
				        i++;
				}


				
				}
			
			
			
			}
 
            printf("%.2f\n",ans);
        }
 
 
    }
 
 
 
 
  //freopen("CON","r",stdin);
// system("pause");
 
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值