Dijkstra算法:

Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。

问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)

算法的基本思想是:每次找到离源点(上面例子的源点就是 1 号顶点)最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。基本步骤如下:

  • 将所有的顶点分为两部分:已知最短路程的顶点集合 P 和未知最短路径的顶点集合 Q。最开始,已知最短路径的顶点集合 P 中只有源点一个顶点。我们这里用一个vis[i]数组来记录哪些点在集合 P 中。例如对于某个顶点 i,如果vis[i]为 1 则表示这个顶点在集合 P 中,如果 vis [i]为 0 则表示这个顶点在集合 Q 中。
  • 设置源点 s 到自己的最短路径为 0 即 dis=0。若存在源点有能直接到达的顶点 i,则把 dist[ i ]设为 e[s][i]。同时把所有其它(源点不能直接到达的)顶点的最短路径为设为 ∞。
  • 在集合 Q 的所有顶点中选择一个离源点 s 最近的顶点 u(即 dist[u]最小)加入到集合 P。并考察所有以点 u 为起点的边,对每一条边进行松弛操作。例如存在一条从 u 到 v 的边,那么可以通过将边 u->v 添加到尾部来拓展一条从 s 到 v 的路径,这条路径的长度是 dist[u]+e[u][v]。如果这个值比目前已知的 dist[v]的值要小,我们可以用新值来替代当前 dist[v]中的值。
  • 重复第 3 步,如果集合 Q 为空,算法结束。最终 dist 数组中的值就是源点到所有顶点的最短路径。

Floyd算法:

Floyd算法又称为插点法,理解起来也很方便,复杂度为o(n3),如要从结点1到结点n,可以由1直通n,再逐渐向其中插入其他结点作为中转点,不断更新在插入结点后的最短路径。

代码也很简洁,四行的算法。

 for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
e[j][k]=min(e[j][i]+e[i][k],e[j][k]);

 Spfa:

SPFA的思路比较简单,网上的说法也比较统一,NOCOW和百度百科上都有。这里在网上找到讲的比较通俗易懂的:

*SPFA(Shortest Path Faster Algorithm) *是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算。 算法大致流程是用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素, 并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。 它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径,可以处理负边。

SPFA 在形式上和BFS非常类似,不同的是BFS中一个点出了队列就不可能重新进入队列,但是SPFA中 一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本 身被改进,于是再次用来改进其它的点,这样反复迭代下去。

判断有无负环:如果某个点进入队列的次数超过V次则存在负环(SPFA无法处理带负环的图)。

其实吧...Spfa老被卡...最好还是用dijkstra吧

HDU-3790 最短路径(模板题)

Dijkstra版:

这个算法还能利用堆和优先队列进行优化

 #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define INF 0X3f3f3f3f
const ll MAXN = 1e3 + ;
const ll mod = 1e9 + ;
//权值为正
int n, m;
int vis[MAXN];
int dist[MAXN];
int a[MAXN][MAXN];
void Dijkstra(int x,int y)
{
for (int i = ; i <= n; i++)
{
dist[i] = a[x][i];
vis[i] = ;
}
vis[x] = ;
int p;
for (int i = ; i <= n; i++)
{
int minn = INF;
for (int j = ; j <= n; j++)
{
if (!vis[j] && dist[j] < minn)
{
minn = dist[j];
p = j;
}
}
vis[p] = ;
for (int j = ; j <= n; j++)
if (!vis[j] && dist[p] + a[p][j] < dist[j])
dist[j] = dist[p] + a[p][j];//更新这个找到的距离最小的点所连的点的距离
}
}
int main()
{
ios::sync_with_stdio(false);
while (cin >> n >> m && n && m)
{
memset(a,INF,sizeof(a));
for (int i = ; i < m; i++)
{
int x, y, len;
cin >> x >> y >> len;
a[x][y] = len;
a[y][x] = len; //无向图
}
Dijkstra(,n);
cout << dist[n] << endl;
}
}

Dijkstra邻接矩阵版本

 #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define INF 0x3f3f3f3f
const ll MAXN = 1e3 + ;
const ll MOD = 1e9 + ;
const double pi = acos(-);
struct node
{
int v, c;
node(int a = , int b = ) { v = a, c = b; }
bool operator<(const node &a) const
{
if (c == a.c)
return v < a.v;
else
return c > a.c;
}
};
struct Edge
{
int v, cost;
Edge(int _v = , int _cost = ) { v = _v, cost = _cost; }
};
vector<Edge> G[MAXN];
bool vis[MAXN];
int dist[MAXN];
//点的编号从1开始
void Dijkstra(int n, int start)
{
memset(vis, false, sizeof(vis));
for (int i = ; i <= n; i++)
dist[i] = INF;
priority_queue<node> que;
while (!que.empty())
que.pop();
dist[start] = ;
que.push(node(start, ));
node temp;
while (!que.empty())
{
temp = que.top();
que.pop();
int u = temp.v;
if (vis[u])
continue;
vis[u] = true;
for (int i = ; i < G[u].size(); i++)
{
int v = G[temp.v][i].v;
int cost = G[u][i].cost;
if (!vis[v] && dist[v] > dist[u] + cost)
{
dist[v] = dist[u] + cost;
que.push(node(v, dist[v]));
}
}
}
}
void addedge(int u, int v, int w)
{
G[u].push_back(Edge(v, w));
}
void init(int n)
{
for (int i = ; i <= n; i++)
G[i].clear();
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie();
cout.tie();
int n, m;
while (cin >> n >> m && n && m)
{
init(n);
for (int i = ; i < m; i++)
{
int x, y, len;
cin >> x >> y >> len;
addedge(x, y, len);
addedge(y, x, len);
}
Dijkstra(n, );
cout << dist[n] << endl;
}
return ;
}

Dijkstra邻接表写法

Floyd版:

 #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define INF 0X3f3f3f3f
const ll MAXN = 1e3 + ;
const ll mod = 1e9 + ;
//可处理权值为负的情况
int n,m;
int e[MAXN][MAXN];
void floyd()
{
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
e[j][k]=min(e[j][i]+e[i][k],e[j][k]);
}
int main()
{
while(cin>>n>>m&&n&&m)
{
memset(e,INF,sizeof(e));
for(int i=;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
e[a][b]=c;
e[b][a]=c;
}
floyd();
cout<<e[][n]<<endl;
}
return ;
}

Floyd版

Spfa:

 #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define INF 0x3f3f3f3f
const ll MAXN = 1e5 + ;
const ll MOD = 1e9 + ;
const double pi = acos(-);
int dist[MAXN];
bool vis[MAXN];
int pre[MAXN]; //pre[x]记录的是起点为x的链表之首在数组p的位置(相当于头插法)
int n, m;
struct Edge
{
int to; //边的终点
int w; //边的权值
int pre; //同一个起点的上一个边在数组E里的位置
Edge(int _to = , int _w = , int _pre = ) { to = _to, w = _w, pre = _pre; }
} E[MAXN]; //边的数目
void Spfa()
{
queue<int> q;
int g, j; //起点为1, 终点为end
int start = ;
int end = n;
for (int i = ; i <= n; i++)
dist[i] = INF;
dist[start] = ;
q.push(start);
vis[start] = ;
while (!q.empty())
{
g = q.front();
q.pop();
vis[g] = ;
for (j = pre[g]; j != -; j = E[j].pre)
{
if (dist[E[j].to] > E[j].w + dist[g]) //能够进行松弛
{
dist[E[j].to] = E[j].w + dist[g];
if (!vis[E[j].to]) //该节点v不在序列中
{
vis[E[j].to] = ;
q.push(E[j].to);
}
}
}
}
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie();
cout.tie();
while (cin >> n >> m && n + m)
{
memset(pre, -, sizeof(pre));
int id = ;
for (int i = ; i < m; i++)
{
int x, y, len;
cin >> x >> y >> len;
E[id].to = y;
E[id].w = len;
E[id].pre = pre[x];
pre[x] = id;
id++;
//双向
E[id].to = x;
E[id].w = len;
E[id].pre = pre[y];
pre[y] = id;
id++;
}
Spfa();
cout << dist[n] << endl;
}
return ;
}//未判负环(如果某个点进入队列的次数超过V次则存在负环

Spfa邻接表

 #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define INF 0X3f3f3f3f
const ll MAXN = 1e3 + ;
const ll mod = 1e9 + ;
int e[MAXN][MAXN]; //邻接矩阵
bool vis[MAXN]; //标记数组
int dist[MAXN]; //源点到顶点i的最短距离
int path[MAXN]; //记录最短路的路径
int enqueue_num[MAXN]; //记录入队次数
int n; //顶点数
int m; //边数
int s; //源点
bool SPFA()
{
memset(vis, , sizeof(vis));
memset(enqueue_num, , sizeof(enqueue_num));
for (int i = ; i <= n; i++)
{
dist[i] = INF;
path[i] = s;
}
queue<int> Q;
Q.push(s);
dist[s] = ;
vis[s] = ;
enqueue_num[s]++;
while (!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = ;
for (int v = ; v <= n; v++)
{
if (e[u][v] != INF) //u与v直接邻接
{
if (dist[u] + e[u][v] < dist[v]) //松弛操作
{
dist[v] = dist[u] + e[u][v];
path[v] = u;
if (!vis[v])
{
Q.push(v);
enqueue_num[v]++;
if (enqueue_num[v] >= n)//说明存在负环
return false;
vis[v] = ;
}
}
}
}
}
return true;
}
/* 到某点的最短path及最短path的len */
void Print()
{
for (int i = ; i <= n; i++)
{
if (i != s)
{
int p = i;
stack<int> st;
cout << "顶点 " << s << " 到顶点 " << p << " 的最短路径是: ";
while (s != p) //路径顺序是逆向的,所以先保存到栈
{
st.push(p);
p = path[p];
}
cout << s;
while (!st.empty()) //依次从栈中取出的才是正序路径
{
cout << "--" << st.top();
st.pop();
}
cout << " 最短路径长度是:" << dist[i] << endl;
}
}
}
int main()
{
while (cin >> n >> m && n && m)
{
s=;
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++)
e[i][j] = INF; //初始化e数组
int u, v, w;
for (int i = ; i < m; i++)
{
cin >> u >> v >> w;
e[u][v] = w;
e[v][u] = w;
}
if (SPFA())
cout<<dist[n]<<endl;
else
cout << "Sorry,it have negative circle!\n"; //存在负环
} return ;
}

Spfa邻接矩阵

最短路径-Dijkstra+Floyd+Spfa的更多相关文章

  1. poj1847 Tram(Dijkstra || Floyd || SPFA)

    题目链接 http://poj.org/problem?id=1847 题意 有n个车站,编号1~n,每个车站有k个出口,车站的出口默认是k个出口中的第一个,如果不想从默认出口出站,则需要手动选择出站 ...

  2. hdoj2544 最短路(Dijkstra || Floyd || SPFA)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2544 思路 最短路算法模板题,求解使用的Dijkstra算法.Floyd算法.SPFA算法可以当做求解 ...

  3. 图论-最短路径<Dijkstra,Floyd>

    昨天: 图论-概念与记录图的方法 以上是昨天的Blog,有需要者请先阅读完以上再阅读今天的Blog. 可能今天的有点乱,好好理理,认真看完相信你会懂得 分割线 第二天 引子:昨天我们简单讲了讲图的概念 ...

  4. Dijkstra,floyd,spfa三种最短路的区别和使用

    这里不列举三种算法的实现细节,只是简单描述下思想,分析下异同 一 Dijkstra Dijkstra算法可以解决无负权图的最短路径问题,只能应付单源起点的情况,算法要求两个集合,开始所有点在第二个集合 ...

  5. 最短路径---Dijkstra/Floyd算法

    1.Dijkstra算法基础: 算法过程比prim算法稍微多一点步骤,但思想确实巧妙也是贪心,目的是求某个源点到目的点的最短距离,总的来说dijkstra也就是求某个源点到目的点的最短路,求解的过程也 ...

  6. 图论算法——最短路径Dijkstra,Floyd,Bellman Ford

    算法名称 适用范围 算法过程 Dijkstra 无负权 从s开始,选择尚未完成的点中,distance最小的点,对其所有边进行松弛:直到所有结点都已完成 Bellman-Ford 可用有负权 依次对所 ...

  7. 四大算法解决最短路径问题(Dijkstra+Bellman-ford+SPFA+Floyd)

    什么是最短路径问题? 简单来讲,就是用于计算一个节点到其他所有节点的最短路径. 单源最短路算法:已知起点,求到达其他点的最短路径. 常用算法:Dijkstra算法.Bellman-ford算法.SPF ...

  8. 单源最短路径Dijkstra算法,多源最短路径Floyd算法

    1.单源最短路径 (1)无权图的单源最短路径 /*无权单源最短路径*/ void UnWeighted(LGraph Graph, Vertex S) { std::queue<Vertex&g ...

  9. 最短路径:Dijkstra & Floyd 算法图解,c++描述

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

随机推荐

  1. Dubbo-本地Bean测试

    Dubbo本地测试API的Bean 一.建立一个测试类文件 二.测试API // 自己要测试的API public static final XxApi xxApi; 三.注入Bean static ...

  2. Scala的正则表达式

    想使用scala的正则表达式,需要首先导入 import scala.util.matching.Regex 然后就可以使用了,实例如下: val pattern = new Regex(" ...

  3. 曹工说Spring Boot源码(6)-- Spring怎么从xml文件里解析bean的

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  4. 五子棋C++版

    当前只完成了单机人人对战  后续会完成联机和AI的实现 定义棋盘 typedef struct { int kind; }Map; //棋盘 0为无子 1为黑子 2为白子 Map maps[line_ ...

  5. [工具] Git版本管理(知识总结)

    对以下文档进行了简要总结,方面复习: [工具] Git版本管理(一)(基本操作) [工具] Git版本管理(二)(分支) [工具] Git版本管理(三)(工作流) [工具] Git版本管理(四)(贡献 ...

  6. 机器学习之路--Matplotlib

    1.绘制折线图 在pandas里面有一种数据类型为datatime ,可以将不规范的日期改为:xxxx-xx-xx import pandas as pd import numpy as np a = ...

  7. 机器学习实战笔记(一)- 使用SciKit-Learn做回归分析

    一.简介 这次学习的书籍主要是Hands-on Machine Learning with Scikit-Learn and TensorFlow(豆瓣:https://book.douban.com ...

  8. Queue and deque

    Queue : 队列 队列(Queue)是常用的数据结构,可以将队列看成特殊的线性表,队列限制了对线性表的访问方式:只能从线性表的一端添加(offer)元素,从另一端取出(poll)元素. 队列遵循先 ...

  9. 生成TFRecord文件完整代码实例

    import os import json def get_annotation_dict(input_folder_path, word2number_dict): label_dict = {} ...

  10. STM32串口遇到的一个问题

    做HLW8032电能表项目中关于USART使用DMA接收定长数据的问题 1:由于HLW8032芯片一上电,芯片就会通过串口每隔50ms向STM32发送24字节的数据,且我不能通过STM32控制HLW8 ...