【算法】单元最短路径之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.步骤 ①对词性歧 ...
随机推荐
- P2764 最小路径覆盖问题 网络流重温
P2764 最小路径覆盖问题 这个题目之前第一次做的时候感觉很难,现在好多了,主要是二分图定理不太记得了,二分图定理 知道这个之后就很好写了,首先我们对每一个点进行拆点,拆完点之后就是跑最大流,求出最 ...
- 线段树 区间加 gcd 差分 小阳的贝壳
小阳的贝壳 如果线段树要维护区间gcd 这个很简单,但是如果有了区间加,维护gcd 就比较麻烦了. 这个首先可以证明的是 gcd(x,y,z)=gcd(x,y-x,z-y) 这个可以推到 n 个 ...
- webpack搭建环境步骤
一.初始化 1.创建文件夹 2.npm init -y 二.安装webpack 和webpack-cli 1.yarn add webpack webpack-cli@3.3.10 -D (这里指定 ...
- 明解JAVA 第三章答案
练习3-1 package candle1220; import java.util.Scanner; public class Nightwatch { public static void mai ...
- Android如何设置只有边框背景透明的背景呢?
很简单,只需要新建一个 drawable 文件 <?xml version="1.0" encoding="utf-8"?> <shape x ...
- C#实现前向最大匹、字典树(分词、检索)
场景:现在有一个错词库,维护的是错词和正确词对应关系.比如:错词“我门”对应的正确词“我们”.然后在用户输入的文字进行错词校验,需要判断输入的文字是否有错词,并找出错词以便提醒用户,并且可以显示出正确 ...
- HTML简单的伪装与造假
利用浏览器制止台能简单的修改内容,致使其造成伪装. 打开网页控制台后,不要管那些眼花撩乱的代码,我们直接寻找控制台顶部的 Tab 栏 找到 Console 这个 Tab,点击它,把代码 documen ...
- struts2 redirectaction
<result type="redirectAction"> <param name="actionName">dashboard< ...
- void 型指针的高阶用法,你掌握了吗?
[导读] 要比较灵活的使用C语言实现一些高层级的框架时,需要掌握一些进阶编程技巧,这篇来谈谈void指针的一些妙用.测试环境采用 IAR for ARM 8.40.1 什么是void指针 void指针 ...
- 【题解】poj 3254 玉米田
假如我们知道第i-1行的有x种放法,那么对于第i行的每一种放法都有x种,所以定义dp[i][j]表示第i行状态为j时的方法数,有转移方程:dp[i][j]=sum(dp[i-1][k]) k表示i-1 ...