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;
}

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/9892891.html