1. 程式人生 > >1033 To Fill or Not to Fill (25 分) 貪心演算法

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: C m a

x ( 100 ) C_​max(≤ 100) , the maximum capacity of the tank;$ D (≤30000)$, the distance between Hangzhou and the destination city; D
a v g ( 20 ) D_​avg(≤20)
, the average distance per unit gas that the car can run; and N ( 500 ) N (≤ 500) , the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: P i P_i ​​ , the unit gas price, and D i ( D ) D_​i(≤D) , the distance between this station and Hangzhou, for i = 1 , , N 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

解題思路

  題目大意: 從某地開車出發,去目標地點,已知每單位油行駛距離、最大油量、目標城市距離,給你沿途所有加油站的資訊,包括油價和距離。求算出 能否到達目標城市,如果能,給出最小的開銷,如果不能給出最遠行駛距離。
  解題思路: 顯然,這是基於貪心演算法的題目,拿最少的錢行駛最遠的距離。
  仔細把兩個Demo好好過一遍,然後注意邊界情況,就能AC,但是貌似測試資料比較變態,需要小心。汽車的油箱最大容量和單位行駛距離都是固定的,那麼每到一個加油站,從該加油站出發,行駛的最大距離也是已知的。我們不妨從第一個加油站開始算,比較可到達範圍內,最便宜的站點是哪個 : ① 如果存在比當前站點還便宜的站點,先到最近的一個站,僅加滿到該地的油即可; ② 如果不存在比當前更便宜的站點,那麼顯然目前這個點是最便宜的,先加滿再說。然後去範圍內相對最便宜的下一個站點;③ 如果下一站不在可達範圍內,如果此時已經臨近終點,那麼輸出總開銷,如果此時終點也不可達,那麼輸出最遠距離。
  更多細節,都在註釋中體現了,詳情參考程式碼。

// https://www.cnblogs.com/XBWer/p/3866486.html
#include<algorithm>
#include<iostream>
using namespace std;
 
struct gasStation 
{
     double pos;
     double price;
} gasst[502];


int main()
{
    double Cmax,D,Davg;
	int N;
    scanf("%lf%lf%lf%d",&Cmax,&D,&Davg,&N);
    int i;
    for(i=0;i<N;i++)
        scanf("%lf%lf",&gasst[i].price,&gasst[i].pos);
    sort(gasst,gasst+N,[](gasStation a,gasStation b){return a.pos<b.pos;});
    if(D==0)
    {
        printf("0.00\n");
        return 0;
    }
    if(gasst[0].pos!=0)
    {
        printf("The maximum travel distance = 0.00\n");
         return 0;
     }
     int curstnum=0;               //當前所處的油站編號,即當前的位置
     double curgas=0;              //當前的油量
     double curcost=0;                //當前的花費
     bool flag=false;              //是否達到目的
     double maxrundis=Cmax*Davg;        //郵箱加滿最遠能行駛的距離    
     while(!flag)
     {
         bool tag=false;            //最大距離內是否有加油站
         bool ifcheaper=false;    //是否有便宜的
         double cheapestprice=10000;    //找出最便宜的
         int cheapestnum;        //沒有更便宜的情況下,找出最便宜的
         for(i=curstnum+1;i<N;i++)
         {
             if((gasst[i].pos-gasst[curstnum].pos)<=maxrundis)    //範圍內
             {
                 tag=true;         //有加油站
                 if(gasst[i].price<gasst[curstnum].price)        
                 {                                            //且有更便宜的,那麼加油 
                     ifcheaper=true;
                     double dist=gasst[i].pos-gasst[curstnum].pos;
                     double needgas=dist/Davg-curgas;
                     curgas=0;
                     curcost+=(needgas*gasst[curstnum].price);
                     curstnum=i;
                     break;
                 }
                 if(gasst[i].price<cheapestprice)//  如果沒有比當前價格更低的,就找一個相對最低的 
                 {
                     cheapestprice=gasst[i].price;
                     cheapestnum=i;
                 }
             }
             else// 沒有加油站 
                 break;
         }
         if(!ifcheaper&&(maxrundis>=(D-gasst[curstnum].pos)))   //說明已經可以到達目的地了
         {
             double dist=D-gasst[curstnum].pos;
             double needgas=dist/Davg-curgas;
             curcost+=needgas*gasst[curstnum].price;
             printf("%.2lf\n",curcost);
             return 0;
         }
         if(tag&&!ifcheaper)            //範圍內不存在更便宜的加油站,但是有加油站 
         {
             double needgas=Cmax-curgas;
             curcost+=(needgas*gasst[curstnum].price);
             double dist=gasst[cheapestnum].pos-gasst[curstnum].pos;
             curgas=Cmax-dist/Davg;
             curstnum=cheapestnum;
         }
         else if(!tag)                        //前方範圍內沒有加油站 
         {
             printf("The maximum travel distance = %.2lf\n",gasst[curstnum].pos+maxrundis);
             return 0;
         }
     }
     return 0;
 }

在這裡插入圖片描述

總結

  這是我做過最難受的一道題了,似乎第4個測試點不是很友好,我做這道題做了兩天,一直通不過,最後不得已,參考了別人的程式碼,發現思路是一樣的,但是不知道我的為啥過不了,可能某個不經意的細節,沒有考慮到吧。雖然很不甘心,但是也沒那麼多時間讓自己研究這個bug,附上自己的程式碼,以後有機會再搞吧。

/*
** @Brief:No.1033 of PAT advanced level.
** @Author:Jason.Lee
** @Date:2018-12-08 
** @status: 
*/
#include<iostream>
#include<algorithm>
using namespace std;

struct gasStation{
	float pi;
	float di;
} gs[501];

int main(){
	float Cmax,D,Davg;
	int N;
	while(cin>>Cmax>>D>>Davg>>N){
		for(int i=0;i<N;i++){
			cin>>gs[i].pi>>gs[i].di;
		}
		sort(gs,gs+N,[](gasStation a,gasStation b){return a.di<b.di;});
		if(D==0){
			printf("0.00\n");
			continue;
		}
		if(gs[0].di!=0.0){// 如果第一個加油站不在起點,那麼無法出發 
			printf("The maximum travel distance = 0.00\n");
			continue;
		}
		int current = 0;
		int next = 0;
		float totalCoast = 0.0;
		float totalDistance = 0.0;
		float capacity = 0.0; 
		while(totalDistance<D){
			// 從當前站開始探測下一站 
			float needGas = 0.0;
			// 最後一站 
			if(current==N-1||gs[current+1].di>gs[current].di+Davg*Cmax) {// 如果下一站不可達,判斷從當前站開始能否到達終點 
				if(totalDistance+Davg*Cmax>=D){
					needGas = (D - totalDistance)/Davg;
					if(capacity<needGas){
						totalCoast += (needGas - capacity)*gs[current].pi;
					}
					totalDistance = D; 
				} else{
					totalDistance += Davg*Cmax;
				}
				break;
			}			
			bool cheaper = false;// 尋找範圍內更便宜的下一站 
			float cheapest = 99999999.0; 
			int cheapestPostion = 0;
			for(next = current+1; next<N&&gs[next].di<=gs[current].di+Davg*Cmax;next++){
				if(gs[next].pi<gs[current].pi){// 如果比當前便宜,那麼先到這個點 
					cheaper = true;
					break;
				}
				if(cheapest>gs[next].pi){
					cheapest = gs[next].pi;
					cheapestPostion = next;
				}
			} 			
			if(cheaper){// 找到下一個更便宜的點
				needGas = (gs[next].di - gs[current].di)/Davg;
				if(capacity<needGas){// 如果不夠用,僅加夠足夠到下一站的油即可 
					needGas = needGas - capacity;// 需要加的油 
					totalCoast += (needGas*gs[current].pi);// 加油對應的開銷 
					capacity += needGas;// 當前油箱油量 
				} 
			}else{// 沒有找到更便宜的點,當前油加滿
				needGas = Cmax - capacity;// 加滿需要的油量 
				totalCoast += needGas * gs[current].pi;// 加油對應的開銷 
				capacity += needGas;
				next = cheapestPostion;// 先到範圍內最便宜的加油站 
			} 
			current = next; // 到達下一站
			capacity -= (gs[current].di - totalDistance)/Davg;
			totalDistance = gs[current].di;
		}
		totalDistance<D ? printf("The maximum travel distance = %.2f\n",totalDistance):printf("%.2f\n",totalCoast);
	}
	return 0;
}

在這裡插入圖片描述