求最短路的几个方法及优化!!!!

看到的结论:
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

最后来个代码总结
求最短路的四种方法模板:https://blog.csdn.net/qq_41117236/article/details/80517605

所以为什么我还要总结呢,因为搜了很多,几乎没见过用优先队列优化的。
写个题
贴个简单的题:
图结构练习——最短路径
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

扫描二维码关注公众号,回复: 4916165 查看本文章

3 2
1 2 1
1 3 1
1 0

Sample Output

1
0

Dijkstra优化

这个是用前向星模拟vector,然后优先队列优化。
#include <bits/stdc++.h>
#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<bits/stdc++.h>
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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43822064/article/details/86476921