EOJ 1855 Solution Report - Expedition

来源:互联网 发布:vnc server windows 编辑:程序博客网 时间:2024/05/22 15:02

原文地址:http://linus-young.github.io/blog/2014/04/15/eoj-1855-solution-report-expedition/


keywords: 贪心 (优先队列)

1. 题目描述

原题地址: EOJ 1855

又是奶牛……

一群奶牛开了一辆漏油车想去一个最近的 town (每行驶一公里漏一升油),离最近 town 的距离为 L 公里, 最初的油量为 P, 在开往 town 的途中有 N 个加油站(每个加油站的油量是 1~100 L)。

求奶牛们为了开到 town, 最少需要在几个加油站停下来加油。 如果不可能到达 town,则输出 -1。 但比较神奇的是:这辆卡车可装的油量没有上限。。。

Note:
1L1,000,000

1P1,000,000

1N10,000

2. 解题思路

解法一 O(n^2)

一开始想的是按照贪心的思想,每次在当前能达到的范围内找油量最多的加油站。

思想是对的,但我想错了,没考虑到每次取最多的,到了最后的话可能油量还不够,又要往回取油量次小的加油站。这样一想一想就昏了,为什么不先排个序啊!!排完序不就可以按照大小顺序取了么。

排序的规则是:

若两个加油站油量相同,则取离起点远的,否则取油量多的。

用 struct 结构体来记录每个加油站的距离(dis)和 油量(fuel), 并将所有的加油站存到一个 vector 中,排序后,卡车上的总油量(total_fuel)初始化为 P,每加一次油就会增加相应的油量,从第一个开始取,若在可取的范围内 (total_fuel > L - dis ),则 total_fuel 增加,并从 vector 中删除该节点。取了该点后判断是否有 total_fuel == L,若成立则返回节点数,否则又从头开始取(因为刚刚最大的已经删掉了),若第一个不是在可取的范围内,也就是说 total_fuel 没有增加,那么就说明不能到达 town, 返回 -1。

需要注意的地方有:

  1. 题目给的是每个加油站到 town 的距离,而非加油站离起点的距离

  2. 题目给的加油站到 town 的距离不一定是排好序的(虽然这个跟本解法没多大关系)

解法二 O(nlogn)

用堆(优先队列)来维护油量

pop_heap 将 front(即第一个最大元素)移动到 end 的前部,同时将剩下的元素重新构造成 (堆排序) 一个新的 heap。

push_heap 对刚插入的(尾部)元素做堆排序。

代码如下:O( n2 )

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
#include <iostream>#include <cstdio>#include <vector>#include <algorithm>using namespace std;// 每次在能达到的范围内油量最大的站加油,注意每停一次后,可达到的范围是动态变化的// 先将所有加油站按照此规则排序// 复杂度: O(n^2)int N, L, P;struct stop {int dis;int fuel;};vector<stop> vec;int cmp(const stop &a, const stop &b){if(a.fuel == b.fuel)return a.dis < b.dis; // 因为 dis 是从 town 到加油站的距离,而非起点到加油站的距离return a.fuel > b.fuel;}int get_minimal_stop(){int total_fuel = P;vector<stop>::iterator it;for(int ans = 0; ans < N; ++ans) {if(total_fuel >= L)return ans;int tmp = total_fuel;for(it = vec.begin(); it != vec.end(); ++it) {if(total_fuel >= L - it->dis) {total_fuel += it->fuel;vec.erase(it);break;}}if(tmp == total_fuel)// no stop was added and before this: total_fuel < L,// so the town is not reachablereturn -1;}return -1;}int main(int argc, char const *argv[]){int dis, fuel;while(scanf("%d", &N) != EOF) {stop tmp;for(int i = 0; i < N; ++i) {scanf("%d%d", &dis, &fuel);tmp.dis = dis;tmp.fuel = fuel;vec.push_back(tmp);}scanf("%d%d", &L, &P);sort(vec.begin(), vec.end(), cmp);cout << get_minimal_stop() << endl;}return 0;}

版本二:O(nlogn)

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
////  main.cpp//  eoj1855_heap////  Created by whyisyoung on 3/17/14.//  Copyright (c) 2014 whyisyoung. All rights reserved.//#include <iostream>#include <cstdio>#include <algorithm>using namespace std;const int maxn = 10005;int N, L, P;struct stop {int dis;int fuel;}Stop[maxn];int heap[maxn];int compare(const stop &a, const stop &b){return a.dis > b.dis;}int main(){while(~ scanf("%d", &N)) {for(int i = 0; i < N; ++i) {scanf("%d%d", &Stop[i].dis, &Stop[i].fuel);}scanf("%d%d", &L, &P);        sort(Stop, Stop + N, compare);int remain = L - P;int ans = 0;int size = 0;int i = 0;while(remain > 0) {for( ; i < N; ++i) {// 当前油用完前能经过的加油站入堆if(Stop[i].dis >= remain) {heap[size++] = Stop[i].fuel;push_heap(heap, heap + size);}// 若当前加油站不能入堆,则下一个也无法入堆elsebreak;}if(size == 0) // 未经过任何一个加油站break;remain -= heap[0];ans++;// 堆顶出栈pop_heap(heap, heap + size);size--;}if(remain > 0)cout << -1 << endl;elsecout << ans << endl;}return 0;}

1 0
原创粉丝点击