最短路径算法题总结

单源最短路径——Dijkstra

时间复杂度:O(n^2)
贪心算法
当图中存在负权值时不适用,改用Folyd

for循环
{
选出最近的点,把该点加入集合
计算从该点出发到其他所有点的距离(排除集合中的点)并更新距离
}

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f

int n, s, e; //n为点的个数,s,e分别为起点终点
int mmap[1000][1000]; //各点之间的距离,若为无向图则对称
int dis[1000], sset[1000] = {0}; //dis为到原点的距离,sset为该点是否加入集合
vector<int> path[1000];  //path为各点到原点的最短路径

void dij(){
    for(int i=0; i<n; i++){
        dis[i] = inf;  
    }
    dis[s] = 0;
    path[s].push_back(s);
    for(int i=0; i<n; i++){
        int mmin = inf;
        int now;
        for(int j=0; j<n; j++){
            if(dis[j] < mmin && sset[j] == 0){
                mmin = dis[j];
                now = j;
            }
        }
        sset[now] = 1;
        for(int j=0; j<n; j++){
            if(sset[j] == 0 && (dis[now] + mmap[now][j] < dis[j])) {
                dis[j] = dis[now] + mmap[now][j];
                path[j] = path[now];
                path[j].push_back(j);
            }
        }
    }
}

int main(){
    cin >> n;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            mmap[i][j] = inf;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++){
            cin >> mmap[i][j];
            if(mmap[i][j] == 100)
                mmap[i][j] = inf;
        }

    cin >> s >> e;
        dij();
    cout << dis[e] << endl;
    for(int i=0; i<path[e].size() - 1; i++)
        cout << path[e][i] << "->";
    cout << path[e][path[e].size() - 1] << endl;
}

全对最短路径——Floyd

时间复杂度: O(n^3)
贪心算法
适用于图中含有正、负权值

步骤:
1⃣️初始化map矩阵
矩阵中map[i][j]的距离为顶点i到顶点j的权值;

如果i和j不相邻,则map[i][j]=∞。
如果i==j,则map[i][j]=0;

2⃣️以顶点A(假设是第k个顶点)为中介点,若a[i][k]+a[k][j] < a[i][j],则设置a[i][j]=a[i][1]+a[1][j]。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f

int n, s, e; //n为点的个数,s,e分别为起点终点
int mmap[1000][1000]; //各点之间的距离,若为无向图则对称
int path[1000][1000]; //path为i,j之间的点

void floyd(){
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++){
            path[i][j] = -1;
        }
    for(int k=0; k<n; k++){
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                if(mmap[i][k] + mmap[k][j] < mmap[i][j]){
                    mmap[i][j] = mmap[i][k] + mmap[k][j];
                    path[i][j] = k;
                }
            }
        }
    }
}

int main(){
    cin >> n;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            mmap[i][j] = inf;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++){
            cin >> mmap[i][j];
            if(mmap[i][j] == 100)
                mmap[i][j] = inf;
        }

    cin >> s >> e;
        floyd();
    cout << mmap[s][e] << endl;
    cout << s << " ";
    vector<int> dis;
    int k = path[s][e];
    while(k != -1){
        dis.push_back(k);
        k = path[s][k];
    }
    for(int i=dis.size()-1; i>=0; i--)
        cout << dis[i] << " ";
    cout << e << endl;
}

SPFA

可以解决带有负权边,负环的问题
例题可参考

https://blog.csdn.net/pursue_my_life/article/details/80201499

初始化代码

void init()
{
    memset(vis, false, sizeof(vis));  //将vis[]数组置为0
    memset(money, false, sizeof(money));  //将money[]数组置为0
    for(int i = 0; i < maxn; ++i)
        memset(cost[i], false, sizeof(cost[i]));  //将cost[][]二维数组置为0
    fill( dis, dis+maxn, inf);  //将dis数组置为inf
}

memset和fill的区别与使用方法

memset:按照字节填充某字符

#include <cstring>
const int INF = 0x3f3f3f3f;
memset(a,INF,sizeof(a));

fill:按照单元赋值,将一个区间的元素都赋予val值

#include <algorithm>
fill(vec.begin(), vec.end(), val); //容器vector
fill(dis, dis+maxn, inf); //一维数组

因为memset函数按照字节填充,所以一般memset只能用来填充char型数组,(因为只有char型占一个字节)。如果填充int型数组,只能填充0、-1 和 inf(正负都行)。因为00000000 = 0,-1同理,如果我们把每一位都填充“1”,会导致变成填充入“11111111”。如果我们将inf设为0x3f3f3f3f,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。无穷小可以将-INF设为0x8f。
而fill函数可以赋值任何值

memset比fill处理速度快一些,所以在能满足需要时,推荐用memset

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值