算法复习:最短路Dijkstra

Dijkstra算法适用范围是单源最短路,有向图或者无向图,不能处理负权值

Floyd算法适用多源最短路,有向图或者无向图,可以处理负权值但是不能处理负权回路

Ford 算法最短路,可以处理负权值,能检测负权回路

Leetcode 743. 网络延迟时间

一、先用Dijkstra算法解,输入是vector要转存一下,另外找的是最后一个传播到的节点所用时间

#define max 999999
#define CLR(donser,value) memset(donser,value,sizeof(donser))
class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int N, int K) 
    {
        int dis[N+1],map[N+1][N+1];
        CLR(dis,max);
        bool visit[N+1];
        CLR (visit,false);
        for(int i=1;i<=N;i++)//先初始化map
            for(int j=1;j<=N;j++)
                map[i][j]=max;
        for(int i=0;i<times.size();i++)//把边转存到map
            map[times[i][0]][times[i][1]]=times[i][2];
        for(int i=1;i<=N;i++)//和起点直接相连的边
        {
            if(i==K)
                dis[i]=0;
            else
                dis[i]=map[K][i];
        }
        visit[K]=true;//起点做标记
        for(int i=1;i<=N;i++)//循环N次
        {
            int min=max,k;
            for(int j=1;j<=N;j++)//找未加入visit的点所连最小边
            {
                if(!visit[j]&&min>dis[j])
                    min=dis[k=j];//k记录取到最小值时的下标
            }
            if(min==max)//不存在没加入的边了
                break;
            visit[k]=true;
            for(int j=1;j<=N;j++)//给没有加入的边更新权值
            {
                if(!visit[j]&&dis[j]>dis[k]+map[k][j])//新加入了K,把与K相连的边加入
                    dis[j]=dis[k]+map[k][j];
            }
        }
        int find=0;
        for(int i=1;i<=N;i++)
            if(dis[i]>find)
                find=dis[i];
        if(find==max)
            return -1;
        else
            return find;
    }
};
leetcode 743

另外,Dijkstra算法模板:

#define N 101
#define max 999999
#define CLR(arr,what) memset(arr,what,sizeof(arr))
int nodenum,edgenum;
int map[N][N],dis[N];
bool visit[N];
int Dijkstra(int src,int des)//输入开始点和结束点
{
    int temp,k;
    CLR(visit,false);
    for(int i=0;i<=nodenum;i++)//先把和开始点直接相连的边找出来
    {
        if(i==src)
            dis[i]=0;//dis[i]存连入i的边,起始点赋0
        else
            dis[i]=map[src][i];
    }
    visit[src]=true;//起始点做标记
    dis[src]=0;
    for(int i=1;i<=nodenum;i++)//做i次循环
    {
        temp=max;
        for(int j=1;j<=nodenum;j++)//寻找没有加入visit的节点中权值最小的
        {
            if(!visit[j]&&temp>dis[j])
                temp=dis[k=j];
        }
        if(temp==max)//不存在没有加入的边时结束
            break;
        visit[k]=true;//访问标记
        for(int j=1;j<=nodenum;j++)//加入k点以后更新和k相连的边
        {
            if(!visit[j]&&dis[j]>dis[k]+map[k][j])
                dis[j]=dis[k]+map[k][j];
        }
    }
    return dis[des];
}
DJ模板

Leetcode 743. 网络延迟时间

二、改用Floyd算法解决,floyd三层循环更新二维表,本质上就是借助一个中间点实现节点更新,时间复杂度:O(N^3)

#define max 999999
class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int N, int K) 
    {
        int map[N+1][N+1];
        for(int i=1;i<=N;i++)//先初始化map 对角线0,其他max
            for(int j=1;j<=N;j++)
                map[i][j]=(i==j?0:max);
        for(int i=0;i<times.size();i++)//把边转存到map
            map[times[i][0]][times[i][1]]=times[i][2];
        for(int k=1;k<=N;k++)
        {
            int lable=0;
            for(int i=1;i<=N;i++)
                for(int j=1;j<=N;j++)
                    if(map[i][k]<max&&map[k][j]<max&&map[i][j]>map[i][k]+map[k][j])
                        map[i][j]=map[i][k]+map[k][j];
        }
        int find=0;
        for(int i=1;i<=N;i++)
        {
            if(map[K][i]>find)
                find=map[K][i];
        }  
        if(find==max)
            return -1;
        else
            return find;
    }
};
leetcode 743

Floyd核心代码:

for(int k=1;k<=N;k++)
  for(int i=1;i<=N;i++)
    for(int j=1;j<=N;j++)
      if(map[i][k]<max&&map[k][j]<max&&map[i][j]>map[i][k]+map[k][j])
        map[i][j]=map[i][k]+map[k][j];

Leetcode 743. 网络延迟时间

三、改用Bellman-Ford算法,最外层循环节点数-1次,内层循环遍历所有的边值更新权值表,时间复杂度O(NM)

l#define max 999999
#define CLR(donser,value) memset(donser,value,sizeof(donser))
class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int N, int K) 
    {
        int dis[N+1];
        CLR(dis,max);
        dis[K]=0;
        for(int k=1;k<=N-1;k++)//第一个点是确定的,循环次数-1
        {
            for(int i=0;i<times.size();i++)//遍历所有边
            {
                if(dis[times[i][0]]<max&&times[i][2]<max&&dis[times[i][0]]+times[i][2]<dis[times[i][1]])
                    dis[times[i][1]]=dis[times[i][0]]+times[i][2];
            }
        }
        int find=0;
        for(int i=1;i<=N;i++)
            if(dis[i]>find)
                find=dis[i];
        if(find>=max)
            return -1;
        else
            return find;
    }
};
leetcode 743

Ford核心代码:

for(int k = 1; k <= n-1; k++) //进行n-1轮松弛
    for(int i = 1; i <= m; i++) //枚举每一条边
        if(dis[u[i]] != INF && w[i] != INF && dis[u[i]] + w[i] < dis[v[i]]) //尝试对每一条边进行松弛
            dis[v[i]] = dis[u[i]] + w[i];
原文地址:https://www.cnblogs.com/dzzy/p/12348705.html