Dijkstra单源最短路径(可用贪心法解决的三步证明)

一、问题

1.问题描述

给定一个带权有向图G=(V, E),其中每条边的权是非负实数。另外,给定V中的一个顶点,称为源。现在要计算从源到所有其他各顶点的最短路长度。这里路的长度是指路上各边权之和。


2.问题分析

算法描述:

  • 输入的带权有向图是G=(V, E),点集V={1,2, ……,n},顶点v是源。
  • c是一个二维数组,c[i][i]表示边( i ,j )的权。 当( i ,j )不在E 时,c[i][j]是一个大数。
  • dist[i]表示当前从源到顶点i的最短特殊路径长度。
  • d=min(dist[k]+c[k][u]) (k\in S)

  • prove :dist[u]=d

(1)问题最优解可以以贪心选择开始

  • 只经过S中的点,计算到V-S中点的特殊最短路径,V-S中选择使得这样的特殊路径最短的一点u,加入S

  • 证明:集合S初始只含v,选择v直接相连的,边权最短的一点u加入,可以得到最优解

  • 分析:现在只涉及第一点u,那么只要证明了u得到的路径值是最短的

  • 对于点u:不存在c[v][k]<c[v][u] (k属于S),因此dist[u]=c[v][u]

  • 因此贪心选择开始可以得到最优解

(2)最优子结构性质

  • 证明:v到u的最短路径为v-v1-v2-……-vi-u ,那么v-v1-v2-……-vi是v到vi的最短路径

  • 设v-v1-v2-……-vi的路径长d1,假设存在v到vi的另一条路径是最短路径,长度为d2,满足d2<d1,那么dist[u]=d1+c[vi][u]<d2+c[vi][u],矛盾,假设不成立

  • 问题具有最优子结构性质

(3)步步贪心选择可以得到最优解

  • |S|=s
  • 当s=1时因为最优解可以由贪心选择开始,成立
  • 假设s=k时成立,则s=k+1时
  • 按贪心规则选择V-S中一点u,且只经过S中的点到u的最短路径为d(v , u),对于所有i∈V-S,知道d(v , u) 是d(v , i)中最小的。
  • 假设u到v的最短路径经过了V-S的点,且经过V-S中第一点为x,因为最优子结构性质,此前的路径长一定为d(v , x),设x到u的路径长为d'(x , u)
  • dist[u]=d(v , x) + d'(x , u) < d(v , u) ,因为d'(x , u)>0,所以d(v , x) < d(v , u),与d(v , u) 是d(v , i)中最小矛盾。
  • 因此s=k时成立,步步贪心可以得到最优解

二、算法设计与分析

1.基本思想

设置顶点集合S,v到S中所有点的最短路径已知,不断选择点来扩充S。初始S只含源v,对于V-S中的点k,把只经过S中的点,到k的最短路径称为特殊路径,Dijkstra每次选择V-S中特殊路径最短的点u加入S,而且设置点u的最短路径长为特殊路径长。

2.具体步骤

  • 参数:c[i][i]表示边( i ,j )的权,dist[i]表示v到i的最短路径长度,n是顶点个数,v是源点编号,prev[i]表示到点i的最短路径的倒数第二点的编号(这样相当于建立了一个由i到v的链表,可以打印出路径
  • 辅助:s[i]标记 i 点是否加入S
#define MAXINT 0xfffffff
int **c;
void Djikstra(int n, int v, int dist[], int prev[]){
    bool s[n+1];
    //初始化集合S,和V-S中点的特殊路径长度和路径信息pev
    for(int i=1; i<=n ; i++ ){
        s[i]=false;
        dist[i]=c[v][i];
        if(dist[i]==MAXINT)
            prev[i]=0;
        else
            prev[i]=v;
    }
    dist[v]=0; s[v]=true;


    //Dijkstra计算,将其余n-1个点加入S
    int temp=MAXINT,u;
    for(int i=1;i<n;i++){

        //选出v经过S中点,到V-S中特殊路径长最小的点u,加入S
       temp=MAXINT;u=v;
       for(int j=1; j<=n ;j++){
            if(!s[j]&&dist[j]<temp){
                temp=dist[j];
                u=j;
            }
        }
        s[u]=true;

        //修改V-S中点的特殊路径长度
        for(int j=1; j<=n; j++){
            if(!s[j]){
                if(c[u][j]+dist[u]<dist[j]){
                    dist[j]=c[u][j]+dist[u];
                    prev[j]=u;
                }
            }
        }
    }      

}

3.时空分析

①时间复杂性:初始化O(n),主体部分外循环n-1次,每次内循环执行n次,O(n^2),因此是O(n^2)

②空间复杂度:二维数组储存边权O(n^2),prev和dist数组储存每个点的路径信息O(n),因此O(n^2)

  • 10
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hnu哈哈

请接受直女的么么哒????

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值