1149.旅遊預算
時限:1000ms 內存限制:10000K 總時限:3000ms
描述
一個旅行社需要估算乘汽車從某城市到另一城市的最小費用,沿路有若干加油站,每個加油站收費不一定相同。旅遊預算有如下規則: 若油箱的油過半,不停車加油,除非油箱中的油不可支持到下一站;每次加油時都加滿;在一個加油站加油時,司機要花費2元買東西喫;司機不必爲其他意外情況而準備額外的油;汽車開出時在起點加滿油箱;計算精確到分(1元=100分)。編寫程序估計實際行駛在某路線所需的最小費用。
輸入
第一行爲起點到終點的距離(實數) 第二行爲三個實數,後跟一個整數,每兩個數據間用一個空格隔開。其中第一個數爲汽車油箱的容量(升),第二個數是每升汽油行駛的公里數,第三個數是在起點加滿油箱的費用(精確到分),第四個數是加油站的數量。(〈=50)。接下去的每行包括兩個實數,每個數據之間用一個空格分隔,其中第一個數是該加油站離起點的距離,第二個數是該加油站每升汽油的價格(元/升)。加油站按它們與起點的距離升序排列。所有的輸入都有一定有解。
輸出
共兩行,每行都有換行 第一行爲一個實數和一個整數,實數爲旅行的最小費用,以元爲單位,精確到分,整數表示途中加油的站的N。第二行是N個整數,表示N個加油的站的編號,按升序排列。數據間用一個空格分隔,最後一個數據後也輸出空格,此外沒有多餘的空格。
輸入樣例
516.3
15.7 22.1 20.87 3
125.4 1.259
297.9 1.129
345.2 0.999
輸出樣例
38.09 1
2
解析:額,我剛看到這道題,好像不是很會做,讓我解析一下。每當走到一個站,檢查一下油箱裏的油,若超過一半且能堅持到下一站,按題意就堅決不能加油,若到不了則肯定要加油。若少於一半,且到不了下一站,肯定要加油,若少於一半但能到達下一站,就需要斟酌一下了,可以選擇加滿或者不加,加滿是因爲若這裏的油價便宜就加滿,不加滿是因爲這裏的油價貴。
對於實現,dp函數裏面傳進去一個參數 i ,返回值應是 i 到終點站的最小花費(所以問題的答案就是dp(0))。對於當前的 i ,此時需要檢查它是否能到達下一站,注意此時必定是滿油狀態。那麼遍歷i 後邊到終點站的每一個站,看能否到達其中的一些站。此時可能會發生的情況有如下幾種:情況一直接能到達終點站,那麼直接退出,返回0就可以;情況二看是否已經遍歷過此站,如果有那麼肯定已經記錄了此站到終點站的最小花費(因爲dp函數就是得到第 i 個站到終點站的最下花費,所以肯定會有備忘錄來記錄;情況三就需要進入for函數,遍歷後邊的每一個 j 站,若能到達j 站且油箱還剩一半的油,此時按規定不能加油,所以不加油直接跳到下一個站即j+1檢查,若當前的j站就是終點站則不需要加油,花費記爲0即可,若不是這兩種,就要加油,然後把費用記錄下來,即更新當前i到終點站的費用等與剛剛加油的費用(也就是i到j的費用)加上j到終點站的費用,同時記錄下來加油的站點j。
此時有個問題可能大家會注意到,如果我當前油量不足一半但是我可以到達下一站,那麼我可以選擇加油或者不加油,然後比較這兩者的代價誰更小才記錄啊。這個是正確的,這個解法也恰恰就遵循了這個,因爲在遍歷i後邊的每個站點j時,我都是在當前的j站點加了油,這就是第一種加油的情況,然後我把這種方法的代價給更新到備忘錄裏邊了,但是此時還是在for循環裏邊,循環到下一個j時,此時我是在上一個站點不加油的方法,此時我又得出了新的不加油方法的代價,此時與備忘錄進行代價小的比較,將代價小的寫入。
此時的dp代碼大概如下: