PAT 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​max​​ (≤ 100), the maximum capacity of the tank; D (≤30000), the distance between Hangzhou and the destination city; D​avg​​ (≤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: P​i​​ , the unit gas price, and D​i​​ (≤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

題目解讀

題目大意:汽車從杭州出發可以通過高速公路去任何城市,但是油箱的容量是有限的,路上有很多加油站,每個加油站的價格不同,為汽車設計一個從杭州到終點的最便宜的加油策略。

輸入:第一行:Cmax表示油箱最大容量,D表示杭州到目的地的距離,Davg表示平均每單位的汽油可以讓汽車行駛的距離,N表示途中加油站的數量;接下來 N 行:給出給個加油站的單位油價Pi和杭州(起點)到這個站點的距離Di

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家

輸出:求汽車從杭州到終點的最少花費(精確到兩位小數)。如果不能夠到達,就輸出汽車能夠行駛的最大距離(精確到兩位小數)。

思路分析

核心思想:貪心算法(每次尋找局部最優,在最便宜的加油站加最多的油)。

前期準備:

  • 最終輸出無論是距離還是價格都要求精確到兩位小數,雖然從給出的輸入數據來看,距離、郵箱容量等好像都是整數,但為了操作方便,避免運算過程精度丟失,我們全都用double保存。(再說了,它給出的數據說不定就是坑你的呢?)
  • 設置結構體數組保存每個加油站的單價和到杭州的距離。
  • 按照到杭州的距離對結構體數組排序,因為輸入是無序的。
  • 排序完判斷第1個結構體到杭州的距離是否為0,也就是說最近的加油站是不是在起點。因為題目說了假定剛開始郵箱沒有油,那麼如果起點處沒有加油站,就比欸想開車了,直接輸出並返回吧。

貪心核心:怎麼實現每次都做出局部最優的選擇?

對於任意一個站點:如果我們在這個站點加滿油,那麼最多就可以跑cmax*davg的距離,我們對這個距離段中遇到的加油站情況進行分析:

  • 按順序遍歷【當前位置,當前位置+cmax*davg】中的所有加油站,如果某個加油站的收費低於當前站點,那麼我就在當前站點加油,跑到那個站點去,加多少呢?就加能恰好讓我到達那個加油站的油。這樣我去那個站點加油就能更便宜。
  • 如果當前站點後面有不止一個站點更便宜,怎麼選擇?比如我現在在A,價格是10,後面是 B 價格9, 後面是C 價格8, 我先找到的是B,那我就退出本次循環,剛好加油跑到B去,在B處重新繼續分析。為啥不直接加油去C,如果從當前位置直接加油去C,那麼BC之間的花費單價是當前加油站的價格也就是10,但我如果先去了B,那麼從B到C的油價就是B處的價格9,顯然更便宜。這樣才滿足局部最優。
  • 如果當前位置後面沒有更便宜的加油站呢?
    • 如果我在當前位置最多能達到的最遠距離超過了終點,那麼我直接加油跑到終點,因為後面的站點只會更貴。
    • 如果我不能直接到終點,那麼我肯定是需要加油的,那我就找盡可能地找比較便宜的那個加油站,在當前加油站加滿油之後過去。既然沒有比當前更低價格的了,就讓油箱加到最大值,這樣能保證利益最大化,保證最大的距離使用的是便宜的油。
  • 如果當前位置不能直接到達終點,並且後面沒有加油站了呢?那麼肯定不能到達中終點了,只能到達當前位置+cmax*davg,也就是說在當前位置加滿,能跑多遠是多遠。

總結:

  • 當前位置能到達的範圍中如果存在更便宜的加油站,就加合適的油剛好到達那個加油站。
  • 如果不存在更便宜的,但是當前位置能直接到達終點,那就加合適的油到達終點。
  • 不存在更便宜的,並且不能直接到終點,找到可達的加油站的相對而言最便宜那個,在當前位置加滿油,然後去那個站點。
  • 當前位置不能到終點,並且後面沒有加油站了,輸出能到達的最大距離。

代碼

#include <iostream>
#include <algorithm>
using namespace std;

struct Station {
    // 每單位汽油價格
    double price;
    // 從起點到這裏的距離
    double dis;
}stat[500];

// 對加油站 離起點 從近到遠 排序
bool cmp(Station a, Station b) {
    return a.dis < b.dis;
}

int main() {
    // cmax油箱容量 d 距離 davg 每單位油能跑多遠 n個加油站
    double cmax, d, davg;
    int n;
    cin >> cmax >> d >> davg >> n;
    // 每個加油站的 價格 位置
    for (int i = 0; i < n; ++i) 
        cin >> stat[i].price >> stat[i].dis;
    // 根據離起點的距離排序
    sort(stat, stat + n, cmp);
    // 第一個加油站不在起點,無法起步
    if(stat[0].dis != 0) {
        printf("The maximum travel distance = 0.00");
        return 0;
    } 
    // nowpos當前在哪個加油站,
    int nowpos = 0;
    // nowgas 當前剩餘多少油,total_price 總花費
    double nowgas = 0.00, total_price = 0.00;
    // 油箱加滿一次油,可以跑多遠
    double each_max_run_dis = cmax * davg;
    // 是否到達終點
    bool arrived = false;
    while (!arrived) {
        // 遍歷 【從當前加油站到最遠能跑到的位置】 之間的 全部加油站
        bool exist_stat  = false; // 當前位置後面是否存在可達加油站
        bool exist_cheaper_stat = false; // 是否存在比當前位置更便宜的加油站
        // 不存在比當前便宜的,就找到其中價格最低的
        int min_pos = -1; double min_price = 9999.99;
        for (int i = nowpos + 1; i < n; ++i) {
            // 當前位置到不了這個加油站,退出循環
            if (stat[i].dis - stat[nowpos].dis > each_max_run_dis) {
                // 最多還能走 nowgas * davg
                break;
            }
            exist_stat = true; // 存在可達加油站
            // 如果有比當前加油站價格更低的加油站
            // 算一下恰好跑到那個加油站需要多少油,
            // 加油跑到那個加油站
            if (stat[i].price < stat[nowpos].price) {
                // 設置標誌
                exist_cheaper_stat = true;
                double needgas = (stat[i].dis - stat[nowpos].dis) / davg - nowgas;
                // 加這麼多油,剛好跑到那個加油站,算一下花費
                total_price += stat[nowpos].price * needgas;
                // 到達那個位置后剩餘油量歸0
                nowgas = 0;
                // 改變位置
                nowpos = i;
                // 不再遍歷後面的加油站
                // 比如我現在 在A,價格是10,後面是 B 價格9, 後面是C 價格8
                // 我先找到的是B,那我就剛好加油跑到B去,在B處重新考慮
                // 為啥不直接加油去C,如果從當前位置直接加油去C,那麼BC之間的花費單價是當前加油站的價格也就是10
                // 但我如果先去了B,那麼從B到C的油價就是B處的價格9,顯然更便宜
                // 這樣才滿足局部最優
                break;
            }
            // 如果說我能從當前位置跑1000米,但是在此之間的加油站的價格沒有一個比我現在的價格低
            // 那我就盡量找最便宜的那個,然後在當前位置加滿油,跑到相對而言最便宜的那個加油站去加油
            // 這樣才滿足局部最優(在最便宜的位置加更多的油跑最多的距離)
            // 這個if不會和上面的if同時執行(上面執行完就break了),所以不用加else
            if (stat[i].price < min_price) {
                min_pos = i;
                min_price = stat[i].price;
            }
        }
        // 不存在比當前便宜的,但是當前位置最遠能達到終點
        if (!exist_cheaper_stat && (d - stat[nowpos].dis <= each_max_run_dis)) {
            double needgas = (d - stat[nowpos].dis) / davg - nowgas;
            // 加這麼多油,剛好跑到終點,算一下花費
            total_price += stat[nowpos].price * needgas;
            // 到達終點
            arrived = true;
            break;
        }
        // 不存在比當前便宜的,但是找到了其他加油站中相對最便宜那個
        if (!exist_cheaper_stat && exist_stat) {
            // 後面有加油站,但是都比當前位置的加油站貴
            // 那我就盡量找最便宜的那個,然後在當前位置加滿油,跑到相對而言最便宜的那個加油站去加油
            // 這樣才滿足局部最優(在最便宜的位置加更多的油跑最多的距離)
            double needgas = cmax - nowgas;
            // 在當前位置加滿油,算一下花費
            total_price += stat[nowpos].price * needgas;
            // 到達那個位置后的剩餘油量
            nowgas = cmax - (stat[min_pos].dis - stat[nowpos].dis) / davg;
            // 改變位置
            nowpos = min_pos;
        // 當前位置無法抵達下一個加油站
        } else if (!exist_stat){
            // 最多還能走 cmax * davg
            printf("The maximum travel distance = %.2f", stat[nowpos].dis + each_max_run_dis);
            return 0;
        }
    }
    // while正常結束,說明到達終點
    printf("%.2f", total_price);
    return 0;
}

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

您可能也會喜歡…