搜索与图论——bellman—ford算法、spfa算法求最短路

news/2024/7/15 17:35:11 标签: 算法, 图论

bellman-ford算法 时间复杂度O(nm)

在一般情况下,spfa算法都优于bf算法,但遇到最短路的边数有限制的题时,只能用bf算法

bf算法和dijkstra很像

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 510,M = 10010;

int n,m,k;
int dist[N],backup[N]; //backup备份数组

struct Edge{
    int a,b,w;
}Edge[M]; //存所有边

int bellman_ford(){
    memset(dist,0x3f,sizeof dist);
    dist[1] = 0;
    for(int i = 0;i < k;i ++ ){
        memcpy(backup,dist,sizeof dist); //备份dist,不会出现串联情况
        for(int j = 0;j < m;j ++ ){
            int a = Edge[j].a,b = Edge[j].b,w = Edge[j].w;
            dist[b] = min(dist[b],backup[a] + w);
        }
    }
    if(dist[n] > 0x3f3f3f3f / 2) return 0;
    else return dist[n];
}

int main(){
    cin >> n >> m >> k;
    for(int i = 0;i < m;i ++ ){
        int a,b,w;
        cin >> a >> b >> w;
        Edge[i] = {a,b,w};
    }
    int t = bellman_ford();
    if(!t) cout << "impossible" << endl;
    else cout << t << endl;
    return 0;
}

spfa算法 时间复杂度一般O(m), 最坏O(nm)

基本上单源最短路都可以用spfa来解决

spfa的核心优化思路是:拿我更新过的点来更新别人。一个点如果没有被更新过的话,拿它来更新别人一定是没有效果的,只有该点变小了,该点后面的点才会变小

spfa代码和堆优化dijkstra特别像

spfa算法求最短路

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>

using namespace std;

typedef pair<int,int> PII;

const int N = 150010;

int n,m;
int h[N],w[N],e[N],ne[N],idx;
int dist[N];
bool vis[N];

int add(int a,int b,int c){
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx,idx ++ ;
}

int spfa(){
    memset(dist,0x3f,sizeof dist);
    dist[1] = 0;
    queue<int> q; //队列里存的是变小的a
    q.push(1);
    vis[1] = true;
    while(q.size()){
        int t = q.front();
        q.pop();
        vis[t] = false;
        for(int i = h[t];i != -1;i = ne[i]){
            int j = e[i];
            if(dist[j] > dist[t] + w[i]){
                dist[j] = dist[t] + w[i];
                if(!vis[j]){
                    q.push(j);
                    vis[j] = true;
                }
            }
        }
    }
    if (dist[n] == 0x3f3f3f3f) return 0;
    return dist[n];
}

int main(){
    cin >> n >> m;
    memset(h,-1,sizeof h);
    while(m -- ){
        int x,y,z;
        cin >> x >> y >> z;
        add(x,y,z);
    }
    int t = spfa();
    if(!t) cout << "impossible" << endl;
    else cout << t << endl;
    return 0;
}

spfa算法求负环

spfa算法可以求出负环用的是抽屉原理,即把多于n+1个的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件。

代码在spfa求最短路的模板上稍加改动即可

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>

using namespace std;

typedef pair<int,int> PII;

const int N = 150010;

int n,m;
int h[N],w[N],e[N],ne[N],idx;
int dist[N],cnt[N];
bool vis[N];

int add(int a,int b,int c){
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx,idx ++ ;
}

bool spfa(){
    queue<int> q;
    for(int i = 1;i <= n;i ++ ){ //由于存在的负环1号点可能走不到,所以要把每一个点都推进队列
        vis[i] = true;
        q.push(i);
    }
    vis[1] = true;
    while(q.size()){
        int t = q.front();
        q.pop();
        vis[t] = false;
        for(int i = h[t];i != -1;i = ne[i]){
            int j = e[i];
            if(dist[j] > dist[t] + w[i]){
                dist[j] = dist[t] + w[i];
                cnt[j] = cnt[t] + 1; //最重要的一步,如果j被更新了最短路,那么意味着j点的cnt是前一个点t+1条边达到的
                if(cnt[j] >= n) return true;
                if(!vis[j]){
                    q.push(j);
                    vis[j] = true;
                }
            }
        }
    }
    return false;
}

int main(){
    cin >> n >> m;
    memset(h,-1,sizeof h);
    while(m -- ){
        int x,y,z;
        cin >> x >> y >> z;
        add(x,y,z);
    }
    if(spfa()) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}


http://www.niftyadmin.cn/n/5459406.html

相关文章

#include<初见c语言之指针总结>

第一小节&#xff1a; #include&#xff1c;初见C语言之指针&#xff08;1&#xff09;&#xff1e;-CSDN博客 #add&#xff1c;初见C语言之指针&#xff08;1&#xff09;&#xff1e;-CSDN博客 第二小节&#xff1a; #include&#xff1c;初见c语言之指针…

2024软件设计师备考讲义——UML(统一建模语言)

UML的概念 用例图的概念 包含 <<include>>扩展<<exted>>泛化 用例图&#xff08;也可称用例建模&#xff09;描述的是外部执行者&#xff08;Actor&#xff09;所理解的系统功能。用例图用于需求分析阶段&#xff0c;它的建立是系统开发者和用户反复…

计算机网络目录

北航计算机网络 chapter1 北航计算机网络 chapter2 物理层 北航计算机网络 chapter3 数据链路层 北航计算机网络 chapter4 网络层 北航计算机网络chapter5 传输层 北航计算机网络chapter6 应用层 北航计算机网络 chapter7 IPv6 北航计算机网络 chapter 8 VLAN

云原生(七)、Kubernetes初学 + 裸机搭建k8s集群

Kubernetes简介 Kubernetes&#xff08;通常简称为K8s&#xff09;是一个开源的容器编排平台&#xff0c;最初由Google设计和开发&#xff0c;现在由Cloud Native Computing Foundation&#xff08;CNCF&#xff09;维护。它旨在简化容器化应用程序的部署、扩展和管理。 Kube…

javascript学习记录:location.hash的用法和说明

location.hash 是 JavaScript 中 Web API window.location 对象的一个属性&#xff0c;它返回 URL 的 hash 部分&#xff08;从 ‘#’ 符号开始的部分&#xff09;。这个属性常常用于单页面应用&#xff08;SPA, Single Page Application&#xff09;中&#xff0c;通过改变 UR…

SuccessFactors 如何通过页面查询后台对应的表

一直以来都习惯SAP的查表方式&#xff0c;一直在想sf能在前台查询表是哪个&#xff0c;今天测试fiori的发现有一个debug工具很好&#xff0c;就是浏览器的F12功能。

TDengine 使用爬坑

TDengine 安装 爬坑 使用安装包立即开始 | TDengine 文档 | 涛思数据 (taosdata.com) linux 服务端版本 TDengine-server-3.2.3.0-Linux-x64.rpm (61.2 M) taosTools-2.5.2-Linux-x64-comp3.rpm (0.2 M) windows 客户端版本 TDengine-client-3.2.3.0-Windows-x64.exe (9.…

vue3源码解析——ref和reactive定义响应式的区别

ref 和 reactive 是 Vue 3.0 中用于定义响应式数据的两个新 API。它们有以下区别&#xff1a; ref 定义单个响应式数据 数据类型可以是任意类型。它通常用于定义原始数据类型为响应式数据。返回一个响应式对象&#xff0c;该对象包含一个 .value 属性&#xff0c;可用于获取和设…