Programming Challenges 习题11.6.8

PC/UVa:111008/10201

Adventures in Moving - Part IV

经过8道动态规划的洗礼,这道题已经算很简单的了,这样Programming Challenges上所有适合我的题目都已经搞定了。

为了方便从滑铁卢(武汉武昌武汉大学)搬到一座大城市(武汉东西湖区临空港),我需要从搬家公司租一辆车。但是最近的油价太贵了,我想知道这辆车会花掉我多少油钱。这辆车一公里耗油一升,油箱容积200升。当我从武昌拿到车时,油箱是半满的,当我在东西湖区还车的时候,油箱也必须至少半满的,否则租车公司会额外收我钱。我想花尽可能少的油费,但是我也不想让车半道没油。😃😃😃

我提前算出了从武昌区到东西湖区的距离,并标记出了每一个加油站距离武昌区的距离,也提前查好了油价,我需要根据这些信息,算出最少的油费。

首先我得知道这路线是不是可达的。如果选定的路线上没有加油站,那么租车公司肯定会扣我钱。另外在有加油站的情况下,每两个加油站之间的距离也不能太长,要不然就会半道没油。在保证我能搬过去的情况下,再来计算油费。

当我从第i个加油站出发时(第0个就相当于从武昌出发),根据在路过的每个加油站加油的情况,我肯定能知道这次出发时油箱里还有多少油,以及花了多少钱。当我开到第i + 1个加油站时,油会变少,然后加一点油保证后面的路程,因此可以根据第i个加油站出发时的剩余油量,以及这两个加油站之间的距离,还有加了多少油,算出我从第i + 1个加油站出发时油箱里还有多少油,以及花了多少钱。可能会出现剩余油量相同,但是花钱不同的情况,这样我只取花钱更少的就可以了。

所以当我到达第i个加油站时,根据这个加油站和前面最近加油站之间的距离distance,可以知道从第i - 1个出发时,最少的油量gasdistance,最大的油量是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
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值