• 洛谷 P1951 收费站_NOI导刊2009提高(2) 最短路+二分


    题面

    题目链接

    P1951 收费站_NOI导刊2009提高(2)

    其实还有一道双倍经验

    P1462 通往奥格瑞玛的道路

    题目描述

    在某个遥远的国家里,有n个城市。编号为1,2,3,…,n。

    这个国家的政府修建了m条双向的公路。每条公路连接着两个城市。沿着某条公路,开车从一个城市到另一个城市,需要花费一定的汽油。

    开车每经过一个城市,都会被收取一定的费用(包括起点和终点城市)。所有的收费站都在城市中,在城市间的公路上没有任何的收费站。

    小红现在要开车从城市u到城市v(1 $ leq u,v leq n $ )。她的车最多可以装下 $ s $ 升的汽油。在出发的时候,车的油箱是满的,并且她在路上不想加油。

    在路上,每经过一个城市,她都要交一定的费用。如果某次交的费用比较多,她的心情就会变得很糟。所以她想知道,在她能到达目的地的前提下,她交的费用中最多的一次最少是多少。这个问题对于她来说太难了,于是她找到了聪明的你,你能帮帮她吗?

    输入输出格式

    输入格式

    第一行5个正整数, $ n,m,u,v,s $ ,分别表示有 $ n $ 个城市, $ m $ 条公路,从城市 $ u $ 到城市 $ v $ ,车的油箱的容量为 $ s $ 升。

    接下来的有 $ 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 $ 升的汽油。

    输出格式

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

    如果她无法到达城市 $ v $ ,输出-1

    输入输出样例

    输入样例:

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

    输出样例:

    8
    

    说明

    【数据规模】

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

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

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

    【时空限制】

    1000ms,128M

    思路

    首先看题目的问法,求最大值的最小,可以考虑到二分答案

    首先假定当答案是x,那么他肯定要满足如果不经过交费超过x的点,跑一遍从u到v的最短路一定小于总油量

    于是可以根据此多次跑最短路了

    AC代码

    
    #include<bits/stdc++.h>
    const int maxn=10010;
    const int maxm=50010;
    using namespace std;
    
    int n,m,st,ed,W,wt[maxn];
    int tot,to[maxm<<1],nxt[maxm<<1],head[maxn],len[maxm<<1];
    int l,r,dis[maxn];
    priority_queue< pair<int,int> > q;
    bool vis[maxn],b;
    
    void Dijkstra(int mx)
    {
        for(int i=1;i<=n;i++) dis[i]=INT_MAX/2;
        for(int i=1;i<=n;i++) vis[i]=false;
        dis[st]=0;
        q.push(make_pair(0,st));
        while(!q.empty())
        {
            int u=q.top().second;
            q.pop();
            if(vis[u]) continue;
            vis[u]=true;
            for(int i=head[u];i;i=nxt[i])
            {
                int 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("%d%d%d%d%d",&n,&m,&st,&ed,&W);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&wt[i]);
            r=max(r,wt[i]);
        }
        for(int i=1;i<=m;i++)
        {
            int u,v,w;scanf("%d%d%d",&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[st],wt[ed]);
        do ///不要while! 否则如果wt[st]和wt[ed]相等就不能进循环了
        {
            int mid=(l+r)>>1;
            Dijkstra(mid);
            if(dis[ed]>W) l=mid+1;
            else r=mid,b=true;
        }while(l<r);
        if(b) printf("%d",r);
        else printf("-1");
        return 0;
    }
    

    总结

    这题第一遍做只得了80分,因为写的是while而不是do while,这个错很隐蔽。。如果l=0肯定就不会出这种情况了(吧)(所以我想说的是这样定左边界很灵性)

    另外,判断是否可到终点的时候,放在r这一边也是一时想到(感谢Uranus巨巨)

  • 相关阅读:
    jQuery 中 attr() 和 prop() 方法的区别
    Jquery DOM元素的方法
    超链接的#和javascript:void(0)的区别
    CSS定位之position详解(转载)
    jQuery最佳实践(转载)
    jQuery官方基础教程笔记(转载)
    股票---基金基础知识
    eclipse里面构建maven项目详解(转载)
    sax解析操作XML
    DOM4j操作xml文件
  • 原文地址:https://www.cnblogs.com/Mercury04/p/9740474.html
Copyright © 2020-2023  润新知