【poj 2431】探险

原题网址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();

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值