【题解】通往奥格瑞玛的道路

题目链接

笔者太菜直到现在才开始看最短路加二分……

解:

显然题目要二分,因为根据多年的经验,看到最大值最小,二话不说想二分……

既然问的是收费情况,那我们不妨二分收费情况。

题目都让我们输入交费数组了,不用它用谁呢?

l=1,r=n,开始二分。注意,左右边界是数组下标。

二分前,注意排序,sort一遍即可。同时,这意味着我们需要另一个数组来copy一下原数组。

依次判断中间值,缩小区间。如果当前交费比起点或终点还少的话,绝对不是答案,return false;

继续判断,将这个点的收费大与当前二分的收费的点的vis全部设为已经访问。

前向星存边,,边权就是生命值。

跑一遍堆优化dijkstra即可。

最后,再来判断,当前的最短路值(即所需生命)是否符合要求?符合,则True,不符合,则False.

注意,我们二分的是下标,所以,最后的答案应该是C[l],或者另开一个变量记录好了。(每个人的二分方法不一样,不一定是C[l])

Code:

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#define inf 2147483647
#define int long long
using namespace std;
int n,m,hp,vis[500000],tot,ans;
int dis[500000],head[500000];
int w[500000],c[500000],l,r;
struct edge{
    int next,to,dis;
}e[500000];
inline void add(int x,int y,int z){
    e[++tot].next=head[x];
    e[tot].to=y;
    e[tot].dis=z;
    head[x]=tot;
}
struct node{
    int dis,pos;
    bool operator <(const node&x)const{
        return x.dis<dis;
    }
};
priority_queue<node>q;
bool check(int Nhp){//二分当前money 
    if(w[1]>Nhp||w[n]>Nhp)return false;
    //priority_queue<node>q;
    for(int i=1;i<=n;++i)dis[i]=inf;
    for(int i=1;i<=n;++i)
        if(w[i]>Nhp)vis[i]=true;//要钱太多不走 
        else vis[i]=false;
    dis[1]=0;q.push((node){0,1});//dijkstra 
    while(!q.empty()){
        node tmp=q.top();
        q.pop();
        int x=tmp.pos;
        if(vis[x])continue;
        vis[x]=true;
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].to;
            if(dis[y]>dis[x]+e[i].dis){
                dis[y]=dis[x]+e[i].dis;
                if(!vis[y])q.push((node){dis[y],y});
            }
        }
    }if(dis[n]<=hp)return true;//有命走到 
    else return false;//没命走到 
}
signed main(){
    scanf("%lld%lld%lld",&n,&m,&hp);
    for(int i=1;i<=n;++i)scanf("%lld",&w[i]),c[i]=w[i];
    for(int i=1;i<=m;++i){
        int a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        if(a==b)continue;
        add(a,b,c);add(b,a,c);
    }sort(c+1,c+n+1);
    l=1,r=n;
    if(!check(c[n])){
        printf("AFK
");i
        return 0;
    }ans=c[n];
    while(l<=r){
        int mid=l+r>>1;
        if(check(c[mid]))r=mid-1,ans=c[mid];
        else l=mid+1;
    }printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/h-lka/p/11198864.html