【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();

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章