【算法】单元最短路径之Bellman-Ford算法和SPFA算法
SPFA是经过对列优化的bellman-Ford算法,因此,在学习SPFA算法之前,先学习下bellman-Ford算法。
bellman-Ford算法是一种通过松弛操作计算最短路的算法。
适用条件
1.单源最短路径(从源点s到其它所有顶点v);2.有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图);3.边权可正可负(如有负权回路输出错误提示);4.差分约束系统;
bellman-Ford的具体操作是这样的:
- 初始化,dis数组表示从起点到达第i个点的最短距离。初始化时:dis[i]=edge[起点][i];如果没有边相接,则设为MAXN;
- 循环n-1次,遍历每个边,将dis[边[i].目标节点]=min(dis[边[i].目标节点],dis[边[i].初始节点]+边[i].权值);
- 【可选】检验负权回路:判断边集合中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 dis[v]中。
#include <bits/stdc++.h>
using namespace std;
int n,m;
//Bellman-Ford algorithm
struct Edge
{
int a,b,v;
}edge[];
long long dis[];
void bellman_ford(int x)
{
dis[x]=;
for(int i=;i<=n-;i++)
{
for(int j=;j<=m;j++)
{
dis[edge[j].b]=min(dis[edge[j].b],dis[edge[j].a]+edge[j].v);
}
}
return ;
/*
bool flag = 1; //判断是否含有负权回路
for(int i = 1; i <= m; ++i) if(dis[edge[i].b] > dis[edge[i].a] + edge[i].cost)
{
flag = 0;
break;
}
return flag;
*/
}
int main()
{
int s;
cin>>n>>m>>s;
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].v);
}
for(int i=;i<=n;i++)dis[i]=;
bellman_ford(s);
for(int i=;i<=n;i++)
cout<<dis[i]<<" ";
return ;
}
这个算法在luogu上70分,TLE了两个测试点,因此需要学习一个更牛逼的算法,SPFA,听说这是一个交大的教授发明的。附上原论文连接:https://wenku.baidu.com/view/df249954d4d8d15abe234eff.html
SPFA算法的全称是:Shortest Path Faster Algorithm,是西南交通大学段凡丁于 1994 年发表的论文中的名字。不过,段凡丁的证明是错误的,且在 Bellman-Ford 算法提出后不久(1957 年 )已有队列优化内容,所以国际上不承认 SPFA 算法是段凡丁提出的。
为了避免最坏情况的出现,在正权图上应使用效率更高的Dijkstra算法。若给定的图存在负权边,类似Dijkstra算法等算法便没有了用武之地,SPFA算法便派上用场了。
#include <bits/stdc++.h>
using namespace std;
int n,m,start;
long long dis[],used[],head[];
int num_edge=;
struct Graph
{
int to,w,next;
}graph[];
bool spfa(int x)
{
queue <int> q;
dis[x]=;
used[x]=;
q.push(x);
while(!q.empty())
{
int u=q.front();
q.pop();
used[u]=;
for(int i=head[u];i;i=graph[i].next)
{
int v=graph[i].to;
long long Songchi=dis[u]+graph[i].w;
if(dis[v]>Songchi)
{
dis[v]=Songchi;
if(used[v]==)
{
used[v]=;
q.push(v);
}
}
}
}
return ;
}
void addedge(int from,int to,int dis)//邻接表存边
{
graph[++num_edge].next=head[from];
graph[num_edge].to=to;
graph[num_edge].w=dis;
head[from]=num_edge;
}
int main()
{
memset(head,,sizeof(head));
memset(used,,sizeof(used));
cin>>n>>m>>start;
for(int i=;i<=n;i++)dis[i]=;
for(int i=;i<=m;i++)
{
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
addedge(a,b,w);
}
if(spfa(start))
{
for(int i=;i<=n;i++)
cout<<dis[i]<<" ";
}
}
【算法】单元最短路径之Bellman-Ford算法和SPFA算法的更多相关文章
- 0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论
一.问题描述 0-1背包问题,部分背包问题.分别实现0-1背包的DP算法,部分背包的贪心算法和DP算法. 二.算法原理 (1)0-1背包的DP算法 0-1背包问题:有n件物品和一个容量为W的背包.第i ...
- 【数据结构与算法】字符串匹配(Rabin-Karp 算法和KMP 算法)
Rabin-Karp 算法 概念 用于在 一个字符串 中查找 另外一个字符串 出现的位置. 与暴力法不同,基本原理就是比较字符串的 哈希码 ( HashCode ) , 快速的确定子字符串是否等于被查 ...
- 最短路径——Dijkstra算法和Floyd算法
Dijkstra算法概述 Dijkstra算法是由荷兰计算机科学家狄克斯特拉(Dijkstra)于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图(无 ...
- 最短路径Dijkstra算法和Floyd算法整理、
转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径—Dijkstra算法和Floyd算法 Dijks ...
- 【转】最短路径——Dijkstra算法和Floyd算法
[转]最短路径--Dijkstra算法和Floyd算法 标签(空格分隔): 算法 本文是转载,原文在:最短路径-Dijkstra算法和Floyd算法 注意:以下代码 只是描述思路,没有测试过!! Di ...
- 最小生成树---Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
- 最小生成树——Prim算法和Kruskal算法
洛谷P3366 最小生成树板子题 这篇博客介绍两个算法:Prim算法和Kruskal算法,两个算法各有优劣 一般来说当图比较稀疏的时候,Kruskal算法比较快 而当图很密集,Prim算法就大显身手了 ...
- prim 算法和 kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
- 词性标注算法之CLAWS算法和VOLSUNGA算法
背景知识 词性标注:将句子中兼类词的词性根据上下文唯一地确定下来. 一.基于规则的词性标注方法 1.原理 利用事先制定好的规则对具有多个词性的词进行消歧,最后保留一个正确的词性. 2.步骤 ①对词性歧 ...
随机推荐
- [Linux] Hexo 搭建个人博客
不做笔记出了bug就得重新再看一遍视频 视频来源: https://www.bilibili.com/video/BV1Yb411a7ty?t=75 安装 先安装 nodejs,npm, git 安装 ...
- Spring Cloud Alibaba系列(一)nacos作为服务注册中心
Spring Cloud Alibaba各组件版本关系 Spring Cloud Alibaba Version Sentinel Version Nacos Version RocketMQ Ver ...
- nginx反向代理做负载均衡以及使用redis实现session共享配置详解
1.为什么要用nginx做负载均衡? 首先我们要知道用单机tomcat做的网站,比较理想的状态下能够承受的并发访问在150到200, 按照并发访问量占总用户数的5%到10%技术,单点tomcat的用户 ...
- Java抽象类的学习体会与注意事项
一.定义 抽象类:用abstract声明的class为抽象类. 抽象方法:用abstract声明的方法为抽象方法. 抽象方法特点:只有方法定义,没有方法的实现(函数体) 抽象类的子类都必须实现它的方法 ...
- [hdu3644 A Chocolate Manufacturer's Problem]模拟退火,简单多边形内最大圆
题意:判断简单多边形内是否可以放一个半径为R的圆 思路:如果这个多边形是正多边形,令r(x,y)为圆心在(x,y)处多边形内最大圆的半径,不难发现,f(x,y)越靠近正多边形的中心,r越大,所以可以利 ...
- 聊聊 TypeScript 中的类型保护
聊聊 TypeScript 中的类型保护 在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况: interface Bird { // 独有方法 fly(); // 共有方法 lay ...
- etcd实现服务发现
前言 etcd环境安装与使用文章中介绍了etcd的安装及v3 API使用,本篇将介绍如何使用etcd实现服务发现功能. 服务发现介绍 服务发现要解决的也是分布式系统中最常见的问题之一,即在同一个分布式 ...
- Mysql 常用函数(6)- replace 函数
Mysql常用函数的汇总,可看下面系列文章 https://www.cnblogs.com/poloyy/category/1765164.html replace 的作用 将某些字符串替换成新的字符 ...
- Mybatis极速入门
搭建mybatis的环境 导入相关jar包 mybatis-3.5.3.jar commons-logging-1.1.1.jar log4j-1.2.16.jar cglib-2.2.2.jar a ...
- 【雕爷学编程】Arduino动手做(53)---土壤湿度传感器
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践(动手试试)出真知的理念,以学习和交流为目的,这里准备 ...