通信线路(spfa,二分)

这篇博客介绍了如何利用二分查找结合SPFA(Shortest Path Faster Algorithm)最短路径算法解决一个通信基站电缆升级的问题。在给定的基站网络中,农场主希望指定一条从总站到农场的路径,让电话公司免费升级不超过K条电缆,其余电缆按最贵的价格支付。博主通过二分查找确定最短路径中满足条件的电缆数量,并实现SPFA算法来寻找最短路径。最终,根据算法结果计算出所需的最小费用。
摘要由CSDN通过智能技术生成

在郊区有 NN 座通信基站,PP 条 双向 电缆,第 ii 条电缆连接基站 AiAi 和 BiBi。

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

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

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

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

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

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

输入格式

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

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

输出格式

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

若 11 号基站与 NN 号基站之间不存在路径,则输出 −1−1。

数据范围

0≤K<N≤10000≤K<N≤1000,
1≤P≤100001≤P≤10000,
1≤Li≤1000000

题解:

用二分法找长度,找出最短路中小于这个长度的边为k个的长度

用spfa算法找最短路,如果加入最短路的边小于本次查找的长度就将这个边的权重计为1

#include <cstring>
#include <iostream>
#include <algorithm>
#include<queue>
 
using namespace std;
 
const int N = 100010, M = 100010;
 
int n, m,k;
int dis[N];//当前每个点到1的最短距离
int h[N],w[N],e[N],ne[N],idx;//邻接表储存
bool st[N];
 
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
 
bool spfa(int v)
{
    memset(dis,0x3f,sizeof dis);
    dis[1]=0;
    queue<int> q;//队列记录被更新过距离的点 只有被更新过的点才会更新其他点的距离
    q.push(1);
    st[1]=true;
    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i])//遍历与这个点相连的边
        {
            int j=e[i];
            if(dis[j]>dis[t]+(w[i]>v?1:0))//判断距离是否被更新
            {
                dis[j]=dis[t]+(w[i]>v?1:0);
                if(!st[j])
                    q.push(j);
                {
                    st[j]=true;//记录这个点是否在队列中 如果已经在队列中则不需要再次加入
                }
            }
        }
    }
    return dis[n]<=k;
}
 
 
 
int main()
{
    scanf("%d%d%d", &n, &m,&k);
    memset(h,-1,sizeof h);
    for (int i = 0; i < m; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a,b,c);
        add(b,a,c);
    }
 
   int l=0,r=1e6+1;
     while(l<r)
     {
     	int mid=r+l>>1;
     	if(spfa(mid))r=mid;
     	else l=mid+1;
     }
     if(r!=1e6+1)cout<<r<<endl;
     else cout<<-1<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值