zoukankan      html  css  js  c++  java
  • Luogu P1462 通往奥格瑞玛的道路(最短路+二分)

    P1462 通往奥格瑞玛的道路

    题面

    题目背景

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

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

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

    题目描述

    在艾泽拉斯,有 (n) 个城市。编号为 (1,2,3,...,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 ai, bi leq n)) 。表示城市 (a_i) 和城市 (b_i) 之间有一条公路,如果从城市 (a_i) 到城市 (b_i) ,或者从城市 (b_i) 到城市 (a_i) ,会损失 (c_i) 的血量。

    输出格式:

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

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

    输入输出样例

    输入样例:

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

    输出样例:

    10
    

    说明

    对于 $60 % $ 的数据,满足 (n leq 200,m leq 10000,b leq 200)

    对于 $100 % $ 的数据,满足 (n leq 10000, m leq 50000, b leq 1000000000)

    对于 $100 % $ 的数据,满足 (c_i leq 1000000000, f_i leq 1000000000) ,可能有两条边连接着相同的城市。

    思路

    要是你帮我把这题改对了我就叫你 (100) 声爹。 --Mercury

    然后我改了一行,水星就叫了我 (100) 声爹 (qwq)

    给上他的博客地址: 洛谷 P1951 收费站_NOI导刊2009提高(2) 最短路+二分

    这题其实并不难,枚举最多交费,然后跑最短路,看 (dis[n]) 是否 $ leq b$ ,然后来更新二分的区间就可以做出来了。

    在这里的话我主要枚举水星犯的错误:

    一、看错题目

    这道题和P1951其实是重题,水星先写的P1951。而那道题无解时输出 -1 而非 AFK ,所以水星就写挂了。

    二、二分写挂了

    一开始的时候水星是这么写的:

    while(l<r)
    {
        int mid=(l+r)>>1;
        Dijkstra(mid);
        if(dis[n]>W) l=mid+1;
        else r=mid;
        if(dis[n]!=INT_MAX/2) b=true;
    }
    

    在这里先说明一下,他的距离数组是以 INT_MAX/2 来初始化的, (bool) 变量 b 用来记录有没有可行答案。

    然后他改了一下:

    do
    {
        int mid=(l+r)>>1;
        Dijkstra(mid);
        if(dis[n]>W) l=mid+1;
        else r=mid;
        if(dis[n]!=INT_MAX/2) b=true;
    }while(l<r);
    

    然而正确的写法是:

    do
    {
        int mid=(l+r)>>1;
        Dijkstra(mid);
        if(dis[n]>W) l=mid+1;
        else r=mid,b=true;
    }while(l<r);
    

    二分是真的容易写挂!之前写的树链剖分二分都没有一次性写对。在这里推荐一篇很好的参考博客,供大家学习:

    [曦行夜落]浅谈二分的边界问题

    AC代码

    #include<bits/stdc++.h>
    typedef long long LL;
    const LL maxn=10010;
    const LL maxm=50010;
    const LL INF=0x7fffffff;
    using namespace std;
    
    LL n,m,W,wt[maxn];
    LL tot,to[maxm<<1],nxt[maxm<<1],head[maxn],len[maxm<<1];
    LL l,r,dis[maxn];
    priority_queue< pair<LL,LL> > q;
    bool vis[maxn],b;
    
    void Dijkstra(LL mx)
    {
        for(LL i=1;i<=n;i++) dis[i]=INF;
        for(LL i=1;i<=n;i++) vis[i]=false;
        dis[1]=0;
        q.push(make_pair(0,1));
        while(!q.empty())
        {
            LL u=q.top().second;
            q.pop();
            if(vis[u]) continue;
            vis[u]=true;
            for(LL i=head[u];i;i=nxt[i])
            {
                LL v=to[i];
                if(wt[v]>mx) continue;
                if(dis[u]+len[i]<dis[v])
                {
                    dis[v]=dis[u]+len[i];
                    q.push(make_pair(-dis[v],v));
                }
            }
        }
    }
    
    int main()
    {
        scanf("%lld%lld%lld",&n,&m,&W);
        for(LL i=1;i<=n;i++)
        {
            scanf("%lld",&wt[i]);
            r=max(r,wt[i]);
        }
        for(LL i=1;i<=m;i++)
        {
            LL u,v,w;scanf("%lld%lld%lld",&u,&v,&w);
            to[++tot]=v;nxt[tot]=head[u];len[tot]=w;head[u]=tot;
            to[++tot]=u;nxt[tot]=head[v];len[tot]=w;head[v]=tot;
        }
        l=max(wt[1],wt[n]);
        do
        {
            LL mid=(l+r)>>1;
            Dijkstra(mid);
            if(dis[n]>W) l=mid+1;
            else b=true,r=mid;
        }while(l<r);
        if(b) printf("%lld",r);
        else printf("AFK");
        return 0;
    }
    
    
  • 相关阅读:
    准备 FRM 考试——方法、工具与教训
    930. 和相同的二元子数组 前缀和
    1906. 查询差绝对值的最小值 前缀和
    剑指 Offer 37. 序列化二叉树 二叉树 字符串
    815. 公交路线 BFS
    518. 零钱兑换 II dp 完全背包
    1049. 最后一块石头的重量 II dp
    5779. 装包裹的最小浪费空间 二分
    5778. 使二进制字符串字符交替的最少反转次数 字符串 滑动窗口
    474. 一和零 dp
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9742191.html
Copyright © 2011-2022 走看看