Dijkstra 算法的几种变形

Dijkstra用来就最短路径,在保证最短路径的条件下,可新增一些其他标尺。

1.每个结点拥有点权,在最短路劲的条件下求点权和最大的路劲。

2.每条边新增边权cost,在最短路径的条件下求cost和最小的路径。

3.求最短路径的条数。


问题1,3可参考我的另一篇文章:

https://blog.csdn.net/qq_39304201/article/details/80176476

关键是建立num数组与maxWeight数组。num[i]表示从起点到结点i的最短路径条数,maxWeight[i]表示起点到结点i最大权值和。在更新最短路径时同时更新这两个数组即可。

问题2与问题1差不多,建立cost[]数组,求起点到每个结点i的最小花费cost[i];


问题1代码:

#include <iostream>
const int MAX = 999999;
using namespace std;


void findPath(int dest,int *p)
{
    if(p[dest] == -1)
    {
        cout<<dest;
        return ;

    }
    findPath(p[dest],p);
    cout<<"-"<<dest;
}
int main()
{
    int n,m,origin,dest;                     //结点数,边数
    int i,j;
    cin>>n>>m>>origin>>dest;
    bool visit[n] = {false};     //结点是否被访问过
    int map[n+1][n+1];           //邻接矩阵
    int pre[n+1];                //前缀数组
    int dis[n+1]={0};                //距离数组
    int weight[n+1]={0};             //点权数组
    int maxWeight[n+1]={0};


    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            map[i][j] = MAX;
    for(i=1;i<=n;i++)
        cin>>weight[i];
    for(i=0;i<m;i++)
    {
        int p,q,length;
        cin>>p>>q>>length;
        map[p][q] = length;
        map[q][p] = length;
    }

    for(i=1;i<=m;i++)
        dis[i] = map[origin][i];

    pre[origin] = -1;
    dis[origin] = 0;
    maxWeight[origin] = weight[origin];

    for(i=1;i<=n;i++)
    {
        int minLenth=MAX,minPos=-1;
        for(j=1;j<=n;j++)
        {
            if( !visit[j] && dis[j] < minLenth)
            {
                minLenth = dis[j];
                minPos = j;
            }
        }

        if(minPos == -1)
            break;
        visit[minPos] = true;
        for(j=1;j<=n;j++)
        {
            if(!visit[j] && map[minPos][j] != MAX)  //这里做一个判断,结点j不仅要属于V-s,同时在minPos与j之间必须有边
            {                                       //如果无边的话,肯定是没有必要更新距离的
                if(dis[j] > dis[minPos] + map[minPos][j])          //一条更短的路径
                {
                    pre[j] = minPos;
                    dis[j] = dis[minPos] + map[minPos][j];
                    maxWeight[j] = maxWeight[minPos] + weight[j];
                }
                else if(dis[j] == dis[minPos] + map[minPos][j] )    //新的最短路径
                {
                    if(maxWeight[j] < maxWeight[minPos] + weight[j])
                    {
                        maxWeight[j] = maxWeight[minPos] + weight[j];
                        pre[j] = minPos;
                    }
                }
            }
        }

    }

    cout<<maxWeight[dest]<<endl;
    findPath(dest,pre);

    return 0;
}

这里在更新最短路径时用到了一个判断,即结点j要与前结点有边。可知,如果无边的话就不必更新最短路径。

在只求最短距离时,用dist[j] > dist[minPos] + map[minPos][j]是足够判断的,因为无边则map[minPos][j]必定为无穷大,这个判断必然为假。但是这里需要判断dist[j] == dist[minPos] + map[minPos][j],而minPos有可能为起点,那么若起点与结点j无边的话,这个判断成立,而实际上无需更新。


问题2代码:

void findPath(int dest,int *p)
{
    if(p[dest] == -1)
    {
        cout<<dest;
        return ;

    }
    findPath(p[dest],p);
    cout<<"-"<<dest;
}
int main()
{
    int n,m,origin,dest;                     //结点数,边数
    int i,j;
    cin>>n>>m>>origin>>dest;
    bool visit[n] = {false};     //结点是否被访问过
    int map[n+1][n+1];           //邻接矩阵
    int pre[n+1];                //前缀数组
    int dis[n+1]={0};            //距离数组
    int cost[n+1][n+1]={0};      //边权数组
    int minCost[n+1]={0};        //最小花费数组


    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            map[i][j] = MAX;
            cost[i][j] = MAX;
        }
    for(i=1;i<=m;i++)           //初始化边权
    {
        int p,q,weight;
        cin>>p>>q>>weight;
        cost[p][q] = weight;
        cost[q][p] = weight;
    }
    for(i=0;i<m;i++)            //初始化邻接矩阵
    {
        int p,q,length;
        cin>>p>>q>>length;
        map[p][q] = length;
        map[q][p] = length;
    }

    for(i=1;i<=m;i++)
    {
        dis[i] = map[origin][i];
        minCost[i] = MAX;
    }

    pre[origin] = -1;
    dis[origin] = 0;
    minCost[origin] = 0;

    for(i=1;i<=n;i++)
    {
        int minLenth=MAX,minPos=-1;
        for(j=1;j<=n;j++)
        {
            if( !visit[j] && dis[j] < minLenth)
            {
                minLenth = dis[j];
                minPos = j;
            }
        }

        if(minPos == -1)
            break;
        visit[minPos] = true;
        for(j=1;j<=n;j++)
        {
            if(!visit[j] && map[minPos][j] != MAX)          //这里做一个判断,结点j不仅要属于V-s,同时在minPos与j之间必须有边
            {                                               //如果无边的话,肯定是没有必要更新距离的
                if(dis[j] > dis[minPos] + map[minPos][j])           //一条更短的路径
                {
                    pre[j] = minPos;
                    dis[j] = dis[minPos] + map[minPos][j];
                    minCost[j] = minCost[minPos] + cost[minPos][j];
                }
                else if(dis[j] == dis[minPos] + map[minPos][j] )    //新的最短路径
                {
                    if(minCost[j] > minCost[minPos] + cost[minPos][j] )
                    {
                        minCost[j] = minCost[minPos] + cost[minPos][j];
                        pre[j] = minPos;
                    }
                }
            }
        }

    }

    cout<<minCost[dest]<<endl;
    findPath(dest,pre);

    return 0;
}

与第一个问题几乎没差,设一个cost[][]来储存一条边的权值,minCost[i]表示起点到节点i的最短路径上所花费的最短权值。

与第一个问题不同的是,

第一个问题里,maxWeight[]初始化全为0,而maxWeight[origin]为weight[origin],

而次问题中,minCost[]初始化为max,而minCost[origin]为0.

因为点权是求最大点权和,起点在更新节点i最短路径时,需要节点i的权值和小于两者相加,那么将结点i初始化为0是合理的,否则结点i将不小于加和,与起点直接相连的i无法更新。

同理,最小花费和需要结点i的花费小于加和,那么初始化为max是合理的。


问题3只需在判断时做修改,若是更短的路径,num[j] = num[minPos],如果是新的最短路径,则num[j] += num[minPos]; 


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Dijkstra算法是一种用于计算从源节点到其他所有节点的最短路径的图论算法。它是一种贪心算法,通过不断地选择最短路径节点并标记为已访问,从而不断缩小搜索范围来实现最短路径的求解。Dijkstra算法的时间复杂度为O(n^2)或O(n log n),具体取决于实现方式。 ### 回答2: Dijkstra算法,也称为迪杰斯特拉算法,是一种用于解决单源最短路径问题的经典算法。该算法通过计算从起点到所有其他节点的最短路径,并在过程中逐步找到最短路径。它以荷兰计算机科学家狄克斯特拉(Edsger W. Dijkstra)命名。 Dijkstra算法的基本思想是从起点开始,逐步通过其他节点来确定最短路径。算法使用两个集合:一个集合记录已确定最短路径的节点,另一个集合记录尚未确定最短路径的节点。算法首先初始化起点的最短路径为0,然后选择与起点相连的节点中距离最近的节点,更新起点到这个节点的最短路径长度。接着,再选择与上一个节点相连的未确定最短路径的节点中距离最短的节点,更新最短路径长度。这个过程会一直持续到所有节点都被确定最短路径。 Dijkstra算法通过使用优先队列来选择距离起点最近的节点,从而提高了效率。通过不断计算和更新节点的最短路径长度,算法最终可以得到从起点到其他所有节点的最短路径。 Dijkstra算法在许多应用中被广泛使用,比如路由器中的路由选择、地图导航系统以及网络优化等。它是一种非常有用和高效的算法,能够快速计算出最短路径并帮助解决一些实际问题。 ### 回答3: Dijkstra 算法,也被称为迪杰斯特拉算法,是一种用于解决单源最短路径问题的图算法。它的目标是从一个源点到图中所有其他点的最短路径。 算法的基本思想是采用贪心策略,通过逐步确定源点到其他各点的最短路径。 具体操作步骤如下: 1. 创建一个距离数组dist[],用于存储源点到达每个顶点的最短路径长度。初始时,源点到自身的距离为0,其余顶点到源点的距离为无穷大。 2. 创建一个集合sptSet[],用于记录已经找到最短路径的顶点集合。初始时,该集合为空。 3. 重复下述步骤直到sptSet[]包含所有顶点: a. 从dist[]数组中选择一个最小的值,它对应的顶点不在sptSet[]中,并加入sptSet[]中。 b. 更新dist[]数组,即如果通过新加入的顶点到达其他顶点的路径更短,则更新其距离。 4. 最终,dist[]数组中存储的就是源点到各个顶点的最短路径长度。 Dijkstra 算法的复杂度为O(V^2),其中V为图的顶点数。该算法适用于没有负权边的图。当图中存在负权边时,需要使用其他算法,如Bellman-Ford算法。 在实际应用中,Dijkstra 算法常被用于网络路由问题,优化交通运输中的最短路径等。通过Dijkstra算法,我们可以找到从一个点到其他所有点的最短路径,帮助我们在网路中选择最优路径,提高效率和性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值