【洛谷P1462】通往奥格瑞玛的道路

今天来做最短路的题目

直接看题吧 毕竟洛谷可以直接复制md文件的特性比openjudge好多了

P1462 通往奥格瑞玛的道路

题目背景

在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量。

有一天他醒来后发现自己居然到了联盟的主城暴风城。

在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛。

题目描述

在艾泽拉斯,有 \(n\) 个城市。编号为 \(1,2,3,\ldots,n\)

城市之间有 \(m\) 条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。

每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。

假设 \(1\) 为暴风城,\(n\) 为奥格瑞玛,而他的血量最多为 \(b\),出发时他的血量是满的。如果他的血量降低至负数,则他就无法到达奥格瑞玛。

歪嘴哦不希望花很多钱,他想知道,在所有可以到达奥格瑞玛的道路中,对于每条道路所经过的城市收费的最大值,最小值为多少。

输入格式

第一行 \(3\) 个正整数,\(n,m,b\)。分别表示有 \(n\) 个城市,\(m\) 条公路,歪嘴哦的血量为 \(b\)

接下来有 \(n\) 行,每行 \(1\) 个正整数,\(f_i\)。表示经过城市 \(i\),需要交费 \(f_i\) 元。

再接下来有 \(m\) 行,每行 \(3\) 个正整数,\(a_i,b_i,c_i\)\(1\leq a_i,b_i\leq n\))。表示城市 \(a_i\) 和城市 \(b_i\) 之间有一条公路,如果从城市 \(a_i\) 到城市 \(b_i\),或者从城市 \(b_i\) 到城市 \(a_i\),会损失 \(c_i\) 的血量。

输出格式

仅一个整数,表示歪嘴哦交费最多的一次的最小值。

如果他无法到达奥格瑞玛,输出 AFK

输入输出样例 #1

输入 #1

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

输出 #1

10

说明/提示

对于 \(60\%\) 的数据,满足 \(n\leq 200\)\(m\leq 10^4\)\(b\leq 200\)

对于 \(100\%\) 的数据,满足 \(1\leq n\leq 10^4\)\(1\leq m\leq 5\times 10^4\)\(1\leq b\leq 10^9\)

对于 \(100\%\) 的数据,满足 \(1\leq c_i\leq 10^9\)\(0\leq f_i\leq 10^9\),可能有两条边连接着相同的城市。

Solution

其实一开始我是不大理解题目的 什么叫“对于每条道路经过的的城市收费的最大值,最小值是多少”
就算看不懂也知道这道题要二分()
好啦,其实意思就是 对于每条到终点的路径中,每条路径被收的钱的最大值,在所有路径中取最小值
那二分就是这样的 你想好check函数 然后l和r微调就能出来
主要是昨天写的时候出现一堆很唐的错误
我们对于check函数 其实就是跑一遍最短路(这里用的Dijkstra),如果碰到比需要的值价钱高的节点就不经过,然后如果扣血会死就返回false 否则返回true
为什么要这么干 因为对于每个给定的mid值 我们只需找出一条合法路径 使得该路径上每个点的价格都不高于mid,这样就可以了
不过,这道题有个特点,就是因为它的值是离散化的,所以最终答案一定在给定的点的价钱中出现,可以排序后按序号二分,时间会快很多
而且由于1和n必须经过,所以如果是用连续二分的话,l最好赋值成max(price[1],price[n])
记得开long long
下面看代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,tot,m,b;
int x,y,z;
int head[200005],nex[200005],ver[200005],edge[200005];
ll price[20005];
int vis[20005];
ll d[20005];
priority_queue<pair<ll,int>>q;
ll fprice[20005];
void add(int x,int y,int z){
    ver[++tot]=y;
    edge[tot]=z;
    nex[tot]=head[x];
    head[x]=tot;
}
bool check(ll t){
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n;i++) d[i]=1e9;
    d[1]=0;
    if(price[1]>t||price[n]>t) return false;
    q.push(make_pair(0,1));
    while(!q.empty()){
        int x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i;i=nex[i]){
            int y=ver[i],z=edge[i];
            if(price[y]>t){
                continue;
            }
            if(d[y]>d[x]+z){
                d[y]=d[x]+z;
                q.push(make_pair(-d[y],y));
            }
        }
    }
    if(d[n]>b) return false;
    else return true;
}
void dijkstra(){
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n;i++) d[i]=1e9;
    d[1]=0; 
    q.push(make_pair(0,1));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i;i=nex[i]){
            int y=ver[i],z=edge[i];
            if(d[y]>d[x]+z){
                d[y]=d[x]+z;
                q.push(make_pair(-d[y],y));
            }
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&b);
    for(int i=1;i<=n;i++){
        scanf("%lld",&price[i]);
    }
    for(int i=1;i<=n;i++) fprice[i]=price[i];
    sort(fprice+1,fprice+n+1);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    dijkstra();
    if(d[n]>b){
        printf("AFK");
        system("pause");
        return 0;
    }
    int l=1,r=n,mid;
    while(l<r){
        mid=(l+r)/2;
        if(check(fprice[mid])){
            r=mid;
        }
        else{
            l=mid+1;
        }
    }
    printf("%lld",fprice[l]);
    system("pause");
    return 0;
}
posted @ 2025-03-25 08:07  elainafan  阅读(45)  评论(0)    收藏  举报