单源最短路

单源最短路

•从一个点出发,到达其他顶点的最短路径的长度。

•基本操作:松弛

•d[u]+map[u, v]< d[v]这样的边(u,v)称为紧的(tense),可以对它进行松弛(relax):

d[v] = d[u]+w, pred[v] = u

•最开始给每一个点一个很大的值,dis[v]=inf,从d[s]=0开始,不断的对可以松弛的点进行松弛,不能松弛的时候就已经求出了最短路

Dijkstra算法

•Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止

•可以证明,具有最小的d[i](临时最短路)值的(还没加入最短路)点在此以后无法松弛

•所以每次找最近的点进行松弛操作

注意该算法要求图中不存在负权边

Dijkstra算法也适用于无向图。但不适用于有负权边的图。

•d[1,2] = 2 ,但用Dijkstra算法求得 d[1,2] = 3

算法步骤:

1、在开始之前,认为所有的点都没有进行过计算,dis[i]全部赋值为极大值(dis[i]表示各点当前到源点的最短距离)

2、源点的 dis[start] 值明显为0

3、计算与 start 相邻的所有点的dis值 —— dis[v] = map[s][v]

4、还没算出最短路的点中dis[]最小的一个点u, 其最短路就是当前的dis[u]

5、对于与u相连的所有点v,若dis[u]+map[u][v] 比当前的dis[v]小, 更新dis[v]

6、重复4,5直到源点到所有点的最短路都已求出

const int inf = 0x3f3f3f3f; //需将road及dis初始化为正无穷inf
int n,m;
int dis[maxn];  //储存各个点到源点的最短距离,dis[s]为0
int road[maxn][maxn];   //两点之间直接距离关系
bool vis[maxn];     //判断源点到该点的距离是否为最短距离
void dijkstra(int s)
{
    memset(vis, false, sizeof(vis));//标记是否求出最短路径
    for(int i = 1; i <= n; i++)
        dis[i] = road[s][i];//初始化起点到每一个点的距离
     vis[s] = true;//标记起点到这一点的最小距离已经求出
     dis[s]=0;
    for(int u = 1; u<n; u++)
    {
        int minD = inf,k = -1;
        for(int i = 1; i<= n; i++)
        {
            if(!vis[i]&&dis[i]<minD)
            {
                k = i;//记录下标
                minD = dis[i];//记录最小值
            }
        }
        vis[k] = true;//标记已经访问过
        //松弛操作
        for(int i = 1; i<= n; i++)
        {
            if(!vis[i]&&dis[k]+road[k][i]<dis[i])
            {
                dis[i]=dis[k]+road[k][i];
            }//if
        }//for
    }
}

SPFA算法

•Dijkstra算法每一次松弛的时候bellmanford都要枚举所有的点,而其实有很多点都是不需要枚举的,所以有很多的无效枚举,于是效率显得略低

SPFA算法(Shortest Path Faster Algorithm)每次松弛的时候只需要枚举与上次被松弛的点相连的点就可以了

SPFA算法的实现

先将源点入队,然后重复从队首取出一个顶点,对所有该点指向的顶点进行松弛,如果松弛成功并且该不在队列中,直到队空,即可找出源点到所有顶点的最短距离时间复杂度为O(KM)。M为边数,k是每个点平均入队次数。 

#define N 105
#define inf 0x3f3f3f3f
int res[N];//存储源点到顶点的最短距离的值
int g[N][N];//存储两点之间的直接距离关系
int cnt[N];//每个点入队的次数,判断是否出现负环
int que[N*N];//队列
bool in_que[N];//标记一个点是否在队列中
int front;//队首位置
int rear;//队尾位置
void spfa(int n,int start)
{
    memset(res,inf,sizeof(res));
    memset(in_que,0,sizeof(in_que));
    rear=front=0;
    que[++rear]=start;
    res[start]=0;
    while(front<rear){
        int cur=que[++front];
        in_que[cur]=0;
        int i;
        for(i=1;i<=n;i++){
            if(res[cur]+g[cur][i]<res[i]){
                res[i]=res[cur]+g[cur][i];
                if(!in_que[i]){
                    que[++rear]=i;
                    in_que=1;
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40507857/article/details/81669037
今日推荐