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

P1462 通往奧格瑞瑪的道路

題目背景

在艾澤拉斯大陸上有一位名叫歪嘴哦的神奇術士,他是部落的中堅力量node

有一天他醒來後發現本身竟然到了聯盟的主城暴風城ios

在被衆多聯盟的士兵攻擊後,他決定逃回本身的家鄉奧格瑞瑪spa

題目描述

在艾澤拉斯,有n個城市。編號爲1,2,3,...,n。code

城市之間有m條雙向的公路,鏈接着兩個城市,從某個城市到另外一個城市,會遭到聯盟的攻擊,進而損失必定的血量。ci

每次通過一個城市,都會被收取必定的過路費(包括起點和終點)。路上並無收費站。get

假設1爲暴風城,n爲奧格瑞瑪,而他的血量最多爲b,出發時他的血量是滿的。string

歪嘴哦不但願花不少錢,他想知道,在能夠到達奧格瑞瑪的狀況下,他所通過的全部城市中最多的一次收取的費用的最小值是多少。it

輸入格式

第一行3個正整數,n,m,b。分別表示有n個城市,m條公路,歪嘴哦的血量爲b。io

接下來有n行,每行1個正整數,fi。表示通過城市i,須要交費fi元。class

再接下來有m行,每行3個正整數,ai,bi,ci(1<=ai,bi<=n)。表示城市ai和城市bi之間有一條公路,若是從城市ai到城市bi,或者從城市bi到城市ai,會損失ci的血量。

輸出格式

僅一個整數,表示歪嘴哦交費最多的一次的最小值。

若是他沒法到達奧格瑞瑪,輸出AFK。

輸入輸出樣例

輸入 #1

4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3

輸出 #1

10

說明/提示

對於60%的數據,知足n≤200,m≤10000,b≤200

對於100%的數據,知足n≤10000,m≤50000,b≤1000000000

對於100%的數據,知足ci≤1000000000,fi≤1000000000,可能有兩條邊鏈接着相同的城市。

【思路】

最短路 + dijkstra + 二分答案

【題目大意】

走每一條路都會消耗必定的血量
到每個城市都會話費必定的金錢
求在活着的狀況下通過的城市中交的金錢最多的最少

【題目分析】

【二分】

使最多的最少
很顯然在提示你要用二分答案
二分有兩個選擇:
1.二分血量
2.二分花費最多的城市花的錢
若是二分血量
那處理起來就至關麻煩了
可是若是二分花費
限制了哪些城市不能走
這樣就能夠check在限制以外的城市中能不能活着到達目的地

【最短路】

看活着的狀況
通過的路徑血量消耗不等大於等於歪嘴哦的血量
注意:
即便是等於也是不行的
這樣的話在二分的前提之下(只走花費不超過二分值的城市)
要讓消耗的血量最少
並且消耗的血量是依附於某條路徑的
因此能夠當成路徑的權值來跑

【核心思路】

二分花費最高城市的花費
而後跑dijkstra
由於有了最高花費的限制
因此花費超出二分值的城市就不可以被進行鬆弛操做
用剩下的跑一下最短路
看看最後1-n的最少消耗的血量是否是小於歪嘴哦的血量
若是小於那就返回真
反之返回假

【完整代碼】

#include<iostream> 
#include<cstdio>
#include<cstring>
#include<queue>
#define int long long
using namespace std;

int read()
{
    int sum = 0,fg = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-')fg = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        sum = sum * 10 + c - '0';
        c = getchar();
    }
    return sum * fg; 
}
const int Max = 10004;
int f[Max];
struct node
{
    int y,ne;
    int z;
}a[Max * 10];
int head[Max],sum = 0;
void add(int x,int y,int z)
{
    a[++ sum].y = y;
    a[sum].ne = head[x];
    a[sum].z = z;
    head[x] = sum;
}

struct point
{
    int x;
    int w;
    bool operator < (const point xx) const 
    {
        return xx.w < w;
    }
};
int dis[Max];
bool use[Max];
priority_queue<point>q;
int n,m,hp;
bool check(int mid)
{
    memset(dis,0x3f,sizeof(dis));
    memset(use,false,sizeof(use));
    dis[1] = 0;
    q.push((point){1,0});
    while(!q.empty())
    {
        int x = q.top().x;
        q.pop();
        if(use[x] == true)
            continue;
        use[x] = true;
        for(register int i = head[x];i != 0;i = a[i].ne)
        {
            int awa = a[i].y;
            if(dis[awa] > dis[x] + a[i].z && f[awa] <= mid)
            {
                dis[awa] = dis[x] + a[i].z;
                if(use[awa] == false)
                    q.push((point){awa,dis[awa]});
            }
        }
    }
    if(dis[n] < hp)
        return true;
    return false;
}

signed main()
{
    n = read(),m = read(),hp = read();
    int r = 0;
    for(register int i = 1;i <= n;++ i)
        f[i] = read(),r = max(r,f[i]);
    for(register int i = 1;i <= m;++ i)
    {
        int x = read(),y = read(),z = read();
        add(x,y,z);
        add(y,x,z);
    }
    int qwq = r;
    r ++;
    int l = 0;
    while(l < r)
    {
        int mid = (r + l) >> 1;
        if(check(mid))r = mid;
        else    l = mid + 1;
    }
    if(l == qwq + 1)
    {
        cout << "AFK" << endl;
        return 0;
    }
    cout << l << endl;
    return 0;
}
相關文章
相關標籤/搜索