1. 程式人生 > >洛谷P1462通往奧格瑞瑪的道路題解

洛谷P1462通往奧格瑞瑪的道路題解

題意

題目是給定了一張雙向邊,有邊權的圖,然後讓我們求出一個最小值,滿足一條路徑上的最大的費用小於這個最小值且這條路徑的所損失的血量不超過總血量。

思路

往往這種求最大值的最小值一般就是二分,然後寫個check函式來判斷這個最小值是否滿足條件,如果不滿足條件,就擴大範圍,而如果滿足條件的話就縮小範圍,直到滿足條件。

所以我們就可以二分一個值\(h\)(二分邊界是起點的費用到所有點的費用最大值),跑最短路,並且在跑最短路的時候,每次鬆弛操作時,都要滿只有費用<=\(h\)的點才可以進行鬆弛。但是這個點的坑點和資料太弱,建議做完了這道題可以去挑戰一波資料加強版——

做這個題的時候要注意每次二分時都需要判斷u,v的費用是否滿足條件,然後我們需要尋找到最大值,所以要使用不記錄二分法。

程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
long long lin[1000100], data[1000100], vis[1000100];
long long n, m, b, maxn, cnt, u, v;
struct edge {
    long long from, to, len, nex;
}e[200010];
struct cym {
    long long len, num;
}dis[1000010];
bool operator < (cym a, cym b) 
{
    return a.len > b.len;
}
inline void add(long long u, long long v, long long l)
{
    e[++cnt].from = u;
    e[cnt].to = v;
    e[cnt].len = l;
    e[cnt].nex = lin[u];
    lin[u] = cnt;
}
using std :: priority_queue;
using std :: max;
priority_queue <cym> q;
bool check(long long h)
{
    memset(vis, 0, sizeof(vis));
    if (data[u] > h || data[v] > h)
        return false;
    for (int i = 1; i <= n; i++)
        dis[i].len = 2147483647, dis[i].num = i;
    dis[u].len = 0;
    q.push(dis[u]);
    while(!q.empty())
    {
        cym cur = q.top();
        q.pop();
        if (vis[cur.num] || data[cur.num] > h)
        continue;
        vis[cur.num] = 1;
        for (int i = lin[cur.num]; i; i = e[i].nex)
            if (dis[e[i].to].len > cur.len + e[i].len && data[e[i].to] <= h && !vis[e[i].to])
            {
                dis[e[i].to].len = cur.len + e[i].len;
                    q.push(dis[e[i].to]);
            }
    }
    if (dis[v].len > b)
        return false;
    else
        return true;
}
inline void binary_search()
{
    long long l = 1, r = maxn;
    long long mid = (l + r) >> 1;
    while (l <= r)
    {
        mid = (l + r) >> 1;
        if (check(mid))
        r = mid - 1;
        else
        l = mid + 1;
    }
    if (l == 0)
    printf("-1");
    else
    printf("%lld", l);
}
signed main()
{
//  freopen("roa.in", "r", stdin);
//  freopen("roa.out", "w", stdout);
    scanf("%lld%lld%lld%lld%lld", &n, &m, &u, &v, &b);
    for (long long i = 1; i <= n; i++)
        scanf("%d", &data[i]), maxn = max(maxn, data[i]);
    for (long long i = 1; i <= m; i++)
    {
        long long a, b, c;
        scanf("%lld%lld%lld", &a, &b, &c);
        add(a, b, c);
        add(b, a, c);
    }          
    if (!check(2147483647))
    {          
        printf("-1");
        return 0;
    }      
    binary_search();    
    return 0;                                                                   
}