PC/UVa:111008/10201
Adventures in Moving - Part IV
经过8
道动态规划的洗礼,这道题已经算很简单的了,这样Programming Challenges上所有适合我的题目都已经搞定了。
为了方便从滑铁卢(武汉武昌武汉大学)搬到一座大城市(武汉东西湖区临空港),我需要从搬家公司租一辆车。但是最近的油价太贵了,我想知道这辆车会花掉我多少油钱。这辆车一公里耗油一升,油箱容积200
升。当我从武昌拿到车时,油箱是半满的,当我在东西湖区还车的时候,油箱也必须至少半满的,否则租车公司会额外收我钱。我想花尽可能少的油费,但是我也不想让车半道没油。😃😃😃
我提前算出了从武昌区到东西湖区的距离,并标记出了每一个加油站距离武昌区的距离,也提前查好了油价,我需要根据这些信息,算出最少的油费。
首先我得知道这路线是不是可达的。如果选定的路线上没有加油站,那么租车公司肯定会扣我钱。另外在有加油站的情况下,每两个加油站之间的距离也不能太长,要不然就会半道没油。在保证我能搬过去的情况下,再来计算油费。
当我从第i
个加油站出发时(第0
个就相当于从武昌出发),根据在路过的每个加油站加油的情况,我肯定能知道这次出发时油箱里还有多少油,以及花了多少钱。当我开到第i + 1
个加油站时,油会变少,然后加一点油保证后面的路程,因此可以根据第i
个加油站出发时的剩余油量,以及这两个加油站之间的距离,还有加了多少油,算出我从第i + 1
个加油站出发时油箱里还有多少油,以及花了多少钱。可能会出现剩余油量相同,但是花钱不同的情况,这样我只取花钱更少的就可以了。
所以当我到达第i
个加油站时,根据这个加油站和前面最近加油站之间的距离distance
,可以知道从第i - 1
个出发时,最少的油量gas
是distance
,最大的油量是200
,所以到达时的油量gasArrival
最小是0
,最大是200 - distance
。这样针对每一个gasArrival
,加不同量的油就得到了gasDeparture
。递推公式为Cost[i][gasDeparture] = min(Cost[i - 1][gas] + (gasDeparture - (gas - distance)) * price[i]), gas >= distance
。
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <climits>
#define FULL_GAS 200
#define HALF_GAS (FULL_GAS >> 1)
using namespace std;
int findMinCost(const int totalDistance, const vector<pair<int, int>> &vpGasStation)
{
int lastGasStation = 0;
if (!vpGasStation.empty()){
if (vpGasStation[0].first > HALF_GAS){
return -1;
}
else{
lastGasStation = vpGasStation[0].first;
for (auto iter = vpGasStation.begin() + 1; iter != vpGasStation.end(); iter++)
{
if (iter->first - lastGasStation > FULL_GAS){
return -1;
}
lastGasStation = iter->first;
}
if (totalDistance - lastGasStation > HALF_GAS){
return -1;
}
}
}
else{
return -1;
}
vector<vector<int>> Cost(vpGasStation.size() + 1, vector<int>(FULL_GAS + 1, INT_MAX));
Cost[0][FULL_GAS >> 1] = 0;
lastGasStation = 0;
for (size_t i = 1; i <= vpGasStation.size(); i++)
{
int distance = vpGasStation[i - 1].first - lastGasStation;
for (int gas = distance; gas <= FULL_GAS; gas++)
{
int gasArrival = gas - distance;
if (Cost[i - 1][gas] != INT_MAX){
for (int gasDeparture = gasArrival; gasDeparture <= FULL_GAS; gasDeparture++)
{
int cost = (gasDeparture - gasArrival) * vpGasStation[i - 1].second;
if (Cost[i - 1][gas] + cost < Cost[i][gasDeparture]){
Cost[i][gasDeparture] = Cost[i - 1][gas] + cost;
}
}
}
}
lastGasStation = vpGasStation[i - 1].first;
}
int minCost = INT_MAX;
for (int gas = totalDistance - lastGasStation + HALF_GAS; gas <= FULL_GAS; gas++)
{
if (Cost[vpGasStation.size()][gas] < minCost){
minCost = Cost[vpGasStation.size()][gas];
}
}
return minCost;
}
int main()
{
int T;
cin >> T;
for (int t = 0; t < T; t++)
{
string strLine;
int totalDistance, distance, price;
cin >> totalDistance;
cin.get();
vector<pair<int, int>> vpGasStation;
while (getline(cin, strLine)){
if (strLine.empty()) break;
istringstream iss(strLine);
iss >> distance >> price;
if (distance <= totalDistance){
vpGasStation.push_back(pair<int, int>(distance, price));
}
}
int minCost = findMinCost(totalDistance, vpGasStation);
if (minCost == -1){
cout << "Impossible" << endl;
}
else cout << minCost << endl;
if (t != T - 1) cout << endl;
}
return 0;
}
/*
1
500
100 999
150 888
200 777
300 999
400 1009
450 1019
500 1399
*/