看到的结论:
Dijkstra:适用于权值为非负的图的单源最短路径,用斐波那契堆的复杂度O(E+VlgV)
BellmanFord:适用于权值有负值的图的单源最短路径,并且能够检测负圈,复杂度O(VE)
SPFA:适用于权值有负值,且没有负圈的图的单源最短路径,论文中的复杂度O(kE),k为每个节点进入Queue的次数,且k一般<=2,但此处的复杂度证明是有问题的,其实SPFA的最坏情况应该是O(VE).
Floyd:每对节点之间的最短路径。
先给出结论:
(1)当权值为非负时,用Dijkstra。
(2)当权值有负值,且没有负圈,则用SPFA,SPFA能检测负圈,但是不能输出负圈。
(3)当权值有负值,而且可能存在负圈,则用BellmanFord,能够检测并输出负圈。
(4)SPFA检测负环:当存在一个点入队大于等于V次,则有负环,后面有证明。
此段引用于:http://blog.csdn.net/xiazdong/article/details/8193680
--------------我----------------------是---------------分---------------割------------------------线-------------------------------------
我本来还想整理总结一下各种求最短路的方法呢,一搜发现别人弄的简直完美,贴几个地址地址:
1:floyd算法https://www.cnblogs.com/wangyuliang/p/9216365.html
下面的算法有的用前向星邻接表实现(模拟vector),如果不知道的看我上个贴:
https://blog.csdn.net/weixin_43822064/article/details/86252683
2:Dijkstra算法https://www.bilibili.com/video/av36886088 这个视频看了就能理解原理了。
3:Bellman-Ford算法,这个我个人觉得用不到,因为改进后的SPFA效率比这个高,都用SPFA了。
https://blog.csdn.net/liangzhaoyang1/article/details/51344742
4:SPFA:其实是3的队列优化,就如我说的,都是用SPFA而不是3。
https://blog.csdn.net/qq_40061421/article/details/82054784
所以为什么我还要总结呢,因为搜了很多,几乎没见过用优先队列优化的。
写个题
贴个简单的题:
图结构练习——最短路径
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
给定一个带权无向图,求节点1到节点n的最短路径。
Input
输入包含多组数据,格式如下。
第一行包括两个整数n m,代表节点个数和边的个数。(n<=100)
剩下m行每行3个正整数a b c,代表节点a和节点b之间有一条边,权值为c。
Output
每组输出占一行,仅输出从1到n的最短路径权值。(保证最短路径存在)
Sample Input
3 2
1 2 1
1 3 1
1 0
Sample Output
1
0
Dijkstra优化
这个是用前向星模拟vector,然后优先队列优化。
#include
#define inf 0x3f3f3f
using namespace std;
int m, n;
int vis[111], dis[111];
struct node
{
int x, y; x是距离,y是编号。
};
int Next[111];
struct qq
{
int u, v, w, next;
} p[111111];
bool operator < (node a, node b){ //重载函数,表示在优先队列里排序是怎么排的,是按照x值的从小到大排的。
return a.x > b.x; //从小到大,这个定义是>,是相反的。
}
void betterdis(int st);
int main()
{
while(cin>> n >> m)
{
memset(dis, inf, sizeof(dis));
memset(Next, 0, sizeof(Next));
memset(vis, 0, sizeof(vis));
memset(p, 0, sizeof(p));
int to = 0;
for(int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
p[++to] = (qq){u, v, w, Next[u]};
Next[u] = to;
p[++to] = (qq){v, u, w, Next[v]};
Next[v] = to; //无向图
}
betterdis(1); 算的是从1到其他点的距离。
cout << dis[n] << endl;
}
return 0;
}
void betterdis(int st)
{
priority_queue<node> q;
dis[st] = 0;
q.push((node){0,st});
while(q.size())
{
node now = q.top();
q.pop();
if(vis[now.y]) continue;
vis[now.y] = 1;
for(int i = Next[now.y]; i != 0; i = p[i].next)
{
int u = p[i].u, v = p[i].v, w = p[i].w;
if(!vis[v] && dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push((node){dis[v], v});
}
}
}
}
--------------------------------------------------分割线----------------------------
直接用vector的优先队列优化:
#include
using namespace std;
#define N 11111
#define inf 0x3f3f3f
struct node
{
int di, num; //distance距离的前两个字母di,num是编号。
};
bool operator <(node a, node b)
{
return a.di > b.di;
}
int dis[N], vis[N], m, n;
vector<node> Map[N];
void add(int u, int v, int w)
{
Map[u].push_back((node){w, v});
}
void bettergls(int u, int e);
int main()
{
while(cin >> n >> m)
{
memset(dis, inf, sizeof(dis));
memset(vis, 0, sizeof(vis));
for(int i = 0; i <= n; i++) Map[i].clear();
for(int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
bettergls(1, n); 从某点到某点
}
}
void bettergls(int u, int e)
{
priority_queue<node> q;
dis[u] = 0;
q.push((node){0,u});
while(q.size())
{
node Now = q.top();
q.pop();
if(vis[Now.num] == 1) continue;
vis[Now.num] = 1;
int len = Map[Now.num].size();
for(int i = 0; i < len; i++)
{
int di = Map[Now.num][i].di, num = Map[Now.num][i].num;
if(!vis[num] && dis[num] > dis[Now.num] + di)
{
dis[num] = dis[Now.num] + di;
q.push((node){dis[num], num});
}
}
}
cout << dis[e] << endl;
}
最后补充个SPFA的
#include
#define inf 0x3f3f3f3f
using namespace std;
int tot,n,m;
int g[2*10005],vis[105],d[105];
struct edge{
int u,v,w,next;
}e[2*10005];
void spfa(int st)
{
memset(vis,0,sizeof(vis));
memset(d,inf,sizeof(d));
queue<int>q;
q.push(st);
vis[st]=1;
d[st]=0;
while(q.size())
{
int now=q.front();
q.pop();
vis[now]=0;
for(int i=g[now];i>0;i=e[i].next)
{
int u=e[i].u,v=e[i].v,w=e[i].w;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
}
}
int main(){
while(cin>>n>>m)
{
memset(e,0,sizeof(e));
memset(g,0,sizeof(g));
tot=0;
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
e[++tot]=(edge){u,v,w,g[u]};
g[u]=tot;
e[++tot]=(edge){v,u,w,g[v]};
g[v]=tot;
}
spfa(1);
cout<<d[n]<<endl;
}
return 0;
}