zoukankan      html  css  js  c++  java
  • AcWing340通信线路(dijkstra+二分)(分层图最短路)

    题目地址https://www.acwing.com/problem/content/342/

    题目描述

    在郊区有 N 座通信基站,P 条 双向 电缆,第 i 条电缆连接基站AiiBi。

    特别地,1 号基站是通信公司的总站,N 号基站位于一座农场中。

    现在,农场主希望对通信线路进行升级,其中升级第 i 条电缆需要花费Li。

    电话公司正在举行优惠活动。

    农产主可以指定一条从 1 号基站到 N 号基站的路径,并指定路径上不超过 K 条电缆,由电话公司免费提供升级服务。

    农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。

    求至少用多少钱可以完成升级。

    输入格式

    第1行:三个整数N,P,K。

    第2..P+1行:第 i+1 行包含三个整数Ai,Bi,Li。

    输出格式

    包含一个整数表示最少花费。

    若1号基站与N号基站之间不存在路径,则输出”-1”。

    数据范围

    0K<N1000
    1P10000
    1Li1000000

    题解:这道题可以用二分+单源最短路来解决,而且用二分非常巧妙。枚举答案[0,1e6+1],至于这里的答案区间为什么是这样的,后面再解释。假设当前二分的是x,那么便可以求1的单源最短路,并且将边的权值大于x的边的权值看作为1,小于等于x的边的权值看作为0,那么求出的dis[n]就是在答案为x时,最小需要不用付出代价的边的数量,当dis[n]<=k,则x可以满足,那么就可以继续枚举x的左边,否则枚举x的右边。所以最后求出的是最小的一个x使得dis[n]<=k.至于答案区间[0,1e6+10],0是因为可能会出现k大于等于1到n之间的最少的边的数量,1e6+1,因为可能会出现1到n之间并不相通,那么最后的二分答案就是1e+10,然后就直接输出-1

    AC代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    using namespace std;
    const int N=1010,M=1e4+10;
    typedef pair<int,int> P;
    struct node{
        int from,to,dis,next;
    }edge[M*2];
    int head[N],cnt=0;
    
    void addedge(int u,int v,int w){
        cnt++;
        edge[cnt].from=u;
        edge[cnt].to=v;
        edge[cnt].dis=w;
        edge[cnt].next=head[u];
        head[u]=cnt;
    }
    
    bool dijkstra(int x,int n,int k){
        int dis[n+10],p[n+10]={0};
        memset(dis,0x3f,sizeof(dis));
        priority_queue<P,vector<P>,greater<P> > q;
        q.push(make_pair(0,1));
        dis[1]=0;
        while(!q.empty()){
            P now=q.top();q.pop();
            int u=now.second,s=now.first,w;
            if(p[u]) continue;
            p[u]=1;
            for(int i=head[u];~i;i=edge[i].next){
                if(edge[i].dis>x) w=1;
                else w=0;
                if(dis[edge[i].to]>dis[edge[i].from]+w){
                    dis[edge[i].to]=dis[edge[i].from]+w;
                    q.push(make_pair(dis[edge[i].to],edge[i].to));
                }
            }
        }
        if(dis[n]>k) return true;
        else return false;
    }
    
    int main(){
        int n,m,k;cin>>n>>m>>k;
        int u,v,w;
        memset(head,-1,sizeof(head));
        while(m--){
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        int l=0,r=1e6+1,mid;
        while(l<r){
            mid=l+r>>1;
            if(dijkstra(mid,n,k)) l=mid+1;
            else r=mid;
        }
        if(r==1e6+1) cout<<"-1";
        else cout<<r;
        return 0;
    }

    题解:这道题也可以直接使用分层图最短路来解决

    AC代码

     #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=1010,M=1e4+10;
    struct st{
        int from,to,dis,next;
    }edge[M*2];
    int head[M*2],cnt=0,dis[N][N];
    struct node{
        int j,s,i;
        node(int s,int i,int j):s(s),i(i),j(j){};
        friend bool operator>(node a,node b){
            return a.s>b.s;
        }
    };
    
    void addedge(int u,int v,int w){
        cnt++;
        edge[cnt].from=u;
        edge[cnt].to=v;
        edge[cnt].dis=w;
        edge[cnt].next=head[u];
        head[u]=cnt;
    }
    
    void spfa(int s,int k){
        memset(dis,0x3f,sizeof(dis));
        priority_queue<node,vector<node>,greater<node> >q;
        q.push(node(0,s,0));
        dis[0][s]=0;
        while(!q.empty()){
            node now=q.top();q.pop();
            int u=now.i,j=now.j;
            for(int i=head[u];~i;i=edge[i].next){
                if(dis[j][edge[i].to]>max(dis[j][edge[i].from],edge[i].dis)){
                    dis[j][edge[i].to]=max(dis[j][edge[i].from],edge[i].dis);
                    q.push(node(dis[j][edge[i].to],edge[i].to,j));
                }
                if(j<k&&dis[j+1][edge[i].to]>dis[j][u]){
                    dis[j+1][edge[i].to]=dis[j][u];
                    q.push(node(dis[j+1][edge[i].to],edge[i].to,j+1));
                }
            }
        }
    }
    
    int main(){
        int n,m,k;cin>>n>>m>>k;
        int u,v,w;
        memset(head,-1,sizeof(head));
        while(m--){
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        spfa(1,k);
        int minn=0x3f3f3f3f;
        for(int i=0;i<=k;i++){
            minn=min(minn,dis[i][n]);
        }
        if(minn==0x3f3f3f3f) cout<<"-1";
        else cout<<minn;
        return 0;
    }

    写于:2020/9/5 16:51


    作者:孙建钊
    出处:http://www.cnblogs.com/sunjianzhao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    构建helm chart应用
    关于使用KubeSphere中的docker配置Harbor仓库http访问docker login登陆报错的解决办法
    Harbor配置自签名证书,docker login+web https访问,helm chart推送应用
    Harbor仓库配置https访问
    Chart 文件结构
    helm chart应用使用示例
    docker-compose命令使用说明
    访问Harbor报502 Bad Gateway
    harbor helm仓库使用
    Helm命令日常使用
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/13618726.html
Copyright © 2011-2022 走看看