您的位置:首页 > 编程语言 > C语言/C++

【poj 2431】探险

2016-07-22 15:34 260 查看
原题网址http://poj.org/problem?id=2431

题目翻译:

【问题描述】

  一群奶牛抢了一辆卡车决定前往树林里探险。但是由于他们的驾驶技术太糟,油箱在路上弄破了,所以他们每前进一个单位的路程就会漏掉一个单位的油。为了修好油箱,奶牛们必须前往最近的城市(不会超过1000000单位路程)。在当前位置和城市之间有N个加油站,奶牛可以在加油站加1到100单位的油。

  对于人来说,树林是危险的地方,对奶牛来说,更是这样,所以奶牛门尽可能的少停站加油,幸运的是,这辆卡车的油箱非常大,你可以认为它的容量是无限大的。卡车在离城市P单位时还有L个单位的油。

  你要计算出奶牛们至少要停几站才能到城市,或者奶牛们根本到不了城市。

【输入格式】

  第一行一个整数N,接下来的N行,每行包含两个用空格隔开的整数,分别表示该加油站离城市的距离和最多可以加多少油。最后一行包含的两个整数为P和L。

【输出格式】

  如果卡车能到达城市,输出最少要停的次数,否则输出-1。

【输入样例】

4
4 4
5 2
11 5
15 10
25 10


【输出样例】

2


【样例解释】

  现在卡车离城市25个单位,卡车离有10个单位的油。在路上,有4个加油站,分别距离城市4,5,11,15,分别距离卡车则为21,20,14,10。这些加油站分别最多可加油4,2,5,10个单位。

  开10个单位,加满10单位油,再开4个单位,加满5单位油,接着直接开到城市。

【数据范围】

0<N<=10 000 , 0<P<=1 000 000


题目大意:有一辆车,每走一个单位会消耗一个单位的油,路上有n个加油站,每个在P[i]位置的加油站可以加L[i]单位的油,要求从P开到0需要的最少加油次数。

算法:贪心;

因为车是从坐标P开向0,且每个加油站的坐标属于[0,P],所以先把加油站按坐标P从大到小排序(因为车先经过坐标更大的加油站)。

贪心策略:设车当前不加油能跑的极限位置是R,显然R=当前车的坐标P-邮箱内剩余油L;

在加油站中依次查找坐标值大于等于R的(车能不加油到达的加油站),显然必须在这些加油站中选一个加油站加油,那么选那个加油站呢?应该选能加更多油的加油站加油。

证明:分两种情况:

1.假设在能加最多油的加油站之前加油,则显然不如在能加最多油的加油站优。

2.假设在能加最多油的加油站之后加油,虽然说这一次车的起始位置更为靠前,但是在走到这个位置时会消耗更多的油,也不如最多油的加油站最优。

算法主框架:在汽车能到达的加油站中,查找能加最多油的加油站加油,下一次从这个加油站出发,继续寻找能到达的加油站加油,直到汽车已经能到城市(即R<=0),为止,每加一次,都统计一次次数。如果中途有存在找不到能到达的加油站的情况则说明无解。

查找过程用优先队列优化(注意这里每次加油后不用清空队列,虽然假设的是汽车用完了油,但也可以不用完,在先前油多的加油站多加油)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#define maxn 10010
using namespace std;
int n,P,L;
bool vis[maxn];//标记已经在队列中的加油站
struct data
{
int p,l;
}A[maxn];

struct cmpq
{
bool operator()(data a,data b)
{
return a.l<b.l;
}
};

bool cmp(data a,data b)
{
return a.p>b.p;
}

void solve()
{
sort(A+1,A+n+1,cmp);
priority_queue<data,vector<data>,cmpq>pq;

int R=P-L,ok=1,cnt=0;
while(R>0 && ok)
{
for(int i=1;i<=n;i++)if(A[i].p>=R && !vis[i])
{
pq.push(A[i]);
vis[i]=1;
}

if(!pq.empty())
{
data t=pq.top();pq.pop();
R=R-t.l;//下次汽车能到的极限位置是R-t.l
cnt++;
}
else ok=0;//队列为空则说明没有加油站可以到达,无解

//while(!pq.empty())pq.pop();
}

if(ok)printf("%d\n",cnt);
else printf("-1\n");
}

int main()
{
//freopen("my.in","r",stdin);
//freopen("my.out","w",stdout);

scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&A[i].p,&A[i].l);
}
scanf("%d%d",&P,&L);

solve();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj c++