1. 程式人生 > >P1951 收費站_NOI導刊2009提高(2)

P1951 收費站_NOI導刊2009提高(2)

二分答案+dijkstra

這道題有被改編的另一道題:“通往奧格瑞瑪的道路”,相信你也做過吧。。。

看到“交的費用中最多的一次最少是多少”,就應該想到二分答案了。

所以我們二分費用,判斷最多的費用是一個\(mid\)的時候可不可以成功到達終點。

如何判斷能否成功到達終點?

不要說用SPFA!因為……被卡了。

我們用不被卡的dijkstra的堆優化就可以了。反正又沒有負權邊。

震驚!我這道題被卡了一段時間的原因居然是……

二分寫掛了!

眾所周知,二分答案差不多有兩種主流的寫法,一種兩個變數的,一種三個變數的。

兩個變數的可以實現,並且不容易錯。在while上面寫的條件是l < r

三個變數的實現必須是整數,如果是浮點數你就GG了。在while上的條件是l <= r。我錯在了這個地方,就丟了一半的分!

所以好好寫二分哦!

程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
const int maxn = 10005, maxm = 50005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
struct Edges
{
    ll next, to, weight;
} e[maxm << 1];
ll head[maxn], tot;
ll a[maxn], f[maxn];
ll dist[maxn];
ll n, m, s, t, c;
struct Heapnodes
{
    ll d, u;
    bool operator < (const Heapnodes &rhs) const
    {
        return d > rhs.d;
    }
};
ll read()
{
    ll ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0', ch = getchar();
    return s * ans;
}
void link(ll u, ll v, ll w)
{
    e[++tot] = (Edges){head[u], v, w};
    head[u] = tot;
}
bool check(ll mid)
{
    memset(dist, 0x3f, sizeof dist);
    std::priority_queue<Heapnodes> heap;
    dist[s] = 0; heap.push((Heapnodes){dist[s], s});
    while(!heap.empty())
    {
        Heapnodes x = heap.top(); heap.pop();
        int d = x.d, u = x.u;
        if(d != dist[u]) continue;
        if(f[u] > mid) continue;
        for(ll i = head[u]; i; i = e[i].next)
        {
            ll v = e[i].to;
            if(f[v] > mid) continue;
            if(dist[u] + e[i].weight < dist[v])
            {
                dist[v] = dist[u] + e[i].weight;
                heap.push((Heapnodes){dist[v], v});
            }
        }
    }
    return dist[t] <= c;
}
int main()
{
    n = read(), m = read(), s = read(), t = read(), c = read();
    for(int i = 1; i <= n; i++)
    {
        a[i] = f[i] = read();
    }
    while(m--)
    {
        ll x = read(), y = read(), z = read();
        link(x, y, z); link(y, x, z);
    }
    if(!check(INF))
    {
        printf("-1\n");
        return 0;
    }
    std::sort(a + 1, a + n + 1);
    ll left = 1, right = n, ans = -1;
    while(left <= right)// !!!!
    {
        ll mid = (left + right) >> 1;
        if(check(a[mid])) ans = a[mid], right = mid - 1;
        else left = mid + 1;
    }
    printf("%lld\n", ans);
    return 0;
}