• P1462 通往奥格瑞玛的道路


    P1462 通往奥格瑞玛的道路

    题目背景

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

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

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

    题目描述

    在艾泽拉斯,有n个城市。编号为1,2,3,...,n。

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

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

    假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。

    歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。

    输入输出格式

    输入格式:

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

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

    再接下来有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,可能有两条边连接着相同的城市。

    一道非常有意思的题目啊

    没有好好学二分的我并没有一下子看出来这是一题二分

    实际上

    首先,看见这个问题,就应该想到二分。

    所有类似于“求解所有的最 x 值中的最 x 值”的问题,都应该先想一想用二分答案的方法来写。

    因为二分是一个猜答案的过程。而且快啊 快啊 log啊

    那么核心算法 单源最短路+二分

    这是一个土豪,不怕收费。并且我们二分的答案是收的钱。

    不断二分答案,不满足的情况有三种:

    1 血不够了

    2 最多一次费用超过了我们不断通过二分进行缩小的那个ans(最小值)

    3走不到(等同于2??)

    所以我们在找最短路的过程中 在熟悉的(a+b<c)中 要加上(w[a~b]<=mid)这样的判断。

    同时不要忘了d[n]<=b。

    至于其他,单源最短路就按照模板的打,二分答案就按照模板的打。找一次,judge一次是否满足情况。

    有个技巧。如果mid是INF时就满足不了(你再有钱也不行)就可以直接“-1”了。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <queue>
    #define MN 6666666
    #define INF 9999999999
    #define ll long long
    using namespace std;
    ll h[MN],to[MN],next[MN],val[MN],cnt;
    inline void add(ll u,ll v,ll w){
        to[++cnt]=v, val[cnt]=w, next[cnt]=h[u], h[u]=cnt;
    }
    ll d[MN],w[MN],n,m,b;
    bool vis[MN];
    inline bool spfa(int limit){
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++) d[i]=INF;
        queue<int> q;
        d[1]=0,vis[1]=true,q.push(1);
        while(!q.empty()){
            int u=q.front(); q.pop(),vis[u]=false;
            for(int e=h[u];e;e=next[e]){
                    if(w[to[e]]<=limit&&d[to[e]]>d[u]+val[e]){
                    d[to[e]]=d[u]+val[e];
                    if(!vis[to[e]])vis[to[e]]=true, q.push(to[e]);
                }
            }
        }
    }
    int main(){
        ll l=0,r=0,mid;
        cin>>n>>m>>b;
        for(int i=1;i<=n;i++) cin>>w[i],r=max(r,w[i]); l=max(w[1],w[n]);
        for(ll i=1,u,v,w;i<=m;i++)
            cin>>u>>v>>w, add(u,v,w), add(v,u,w);
        spfa(r);
        if(d[n]==INF||d[n]>b) { printf("AFK"); return 0; }
        while(l<=r)
            spfa(mid=(l+r)>>1)&&d[n]>b ? l=mid+1 : r=mid-1 ;
        printf("%d",l);
        return 0;
    }

    暴力压行好像会变慢啊。。

     

  • 相关阅读:
    SQL学习日志
    程序员之路──如何学习C语言并精通C语言
    using用法
    c#中的接口与类的区别
    用c#来实现一种行列式的计算优化
    python 切换目录
    如何光盘自动运行html?
    nsis 安装脚本示例(转)
    python sys.path.append
    python 面向对象初认识
  • 原文地址:https://www.cnblogs.com/flicker-five/p/10616343.html
Copyright © 2020-2023  润新知