51nod 1288:汽油补给

45 篇文章 0 订阅

题目来源:  Codility
基准时间限制:1 秒 空间限制:131072 KB 分值: 160  难度:6级算法题
 收藏
 取消关注
有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2...... -> N,车每走1个单位距离消耗1个单位的汽油,油箱的容量是T。给出每个城市到下一个城市的距离D,以及当地的油价P,求走完整个旅途最少的花费。如果无法从起点到达终点输出-1。
例如D = {10, 9, 8}, P = {2, 1, 3},T = 15,最小花费为41,在0加上10个单位的汽油,在1加满15个单位的汽油,在2加2个单位的汽油,走到终点时恰好用完所有汽油,花费为10 * 2 + 15 * 1 + 2 * 3 = 41。
Input
第1行:2个数N, T中间用空格分隔,N + 1为城市的数量,T为油箱的容量(2 <= N <= 100000, 1 <= T <= 10^9)。
第2至N + 1行:每行2个数D[i], P[i],中间用空格分隔,分别表示到下一个城市的距离和当地的油价(1 <= D[i], P[i] <= 1000000)。
Output
输出走完整个旅程的最小花费,如果无法从起点到达终点输出-1。
Input示例
3 15
10 2
9 1
8 3
Output示例
41

这个题目一开始一点思路都没有,后来想每次到加油站都将油箱试图加满,如果里面的油都是比自己便宜的,不加。每次都替换油箱中比自己贵的油,然后跑完了一段再算之前的钱。即油先跑着,钱后算账。

把油箱里面的油按价钱分成相应的部分。每段路程车都是满油启动。

代码:

#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#include <set>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;

struct no
{
	ll price;
	ll num;

	bool operator<(const no & n1)
	{
		return price < n1.price;
	}
};
const int maxn = 100005;
ll n, t;
ll dis[maxn], pri[maxn];

void input()
{
	int i, j, k;
	scanf("%lld%lld", &n, &t);

	for (i = 1; i <= n; i++)
	{
		scanf("%lld%lld", &dis[i], &pri[i - 1]);
	}
}

void solve()
{
	int i, j, k;
	vector<no>qu;
	int flag = 1;
	ll res = 0;
	
	for (i = 0; i <= n; i++)
	{
		if (t < dis[i + 1])flag = 0;
		if (flag == 0)continue;

		if (i == 0)
		{
			no n1;
			n1.price = pri[0];
			n1.num = t;
			qu.push_back(n1);
		}
		else
		{
			sort(qu.begin(), qu.end());
			ll di = 0;
			ll rmin = 0;

			while (true)
			{
				if (di + qu[0].num >= dis[i])
				{
					rmin = rmin + (dis[i] - di)*(qu[0].price);
					if (di + qu[0].num >= dis[i])
					{
						qu[0].num = qu[0].num - (dis[i] - di);
					}
					if (qu[0].num == 0)
					{
						qu.erase(qu.begin());
					}
					break;
				}
				else
				{
					di = di + qu[0].num;
					rmin += qu[0].num*qu[0].price;
					qu.erase(qu.begin());
				}
			}
			res += rmin;
			
			ll sum = 0;
			for (k = 0; k < qu.size(); k++)
			{
				if (pri[i] > qu[k].price)
				{
					sum += qu[k].num;
				}
				else
				{
					no n1;
					n1.num = t - sum;
					n1.price = pri[i];
					qu.erase(qu.begin() + k, qu.end());
					qu.push_back(n1);
					sum = t;
					break;
				}
			}
			if (sum < t)
			{
				no n1;
				n1.price = pri[i];
				n1.num = t - sum;
				qu.push_back(n1);
			}
		}
	}
	if (flag == 0)
	{
		puts("-1");
	}
	else
	{
		printf("%lld", res);
	}
}

int main() 
{
//	freopen("i.txt","r",stdin);
//	freopen("o.txt","w",stdout);

	input();
	solve();

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值