Dijkstra

最短路 –单源最短路

1
ps: 单源最短路径代码上和应用上都非常的简单 但是跟人感觉推证它的正确性有些复杂 苦思冥想了好几天 有那么一点头绪 做一下记录
dijkstra的单源最短路径 被认为是求解无负权最短路径问题的最好放法 其中包含了 两个思想 一个是贪心 一个是最优子结构
推理
先解释几个后面需要用到的几个符号w(i,j)表示从i到j的权值 m(i,j)表示i到j的最短路径的权值总和 p(i,v1,v2,v3…,j) 表示i到j的一条路径权值总和
一个定理:如果存在m(i,j)=p(i,v1,v2,v3,j); 则m(i,j)=m(i,v3)+w(v3,j);

用反证法来证明这个定理的正确性 假设如果存在m(i,j)=p(i,v1,v2,v3,j); m(i,j)!=m(i,v3)+w(v3,j)
那么 m(i,j)=p(i,k1,k2…,v3)+w(v3,j) 而p(i,k1,k2…v3)>m(i,v3) 显然与m(i,j)是最短距离矛盾 所以
即可得定理;
此算法的特点是 每次都能选出 一个离 源点最短的点 一共需要n 次即可得到 源点到所有点的最短距离
注意这个n次 是我们初始的时候没有更新 源点到各点的距离 而是全部设为无穷(至少为比权值中最大值还要大1) 如果是 初始化就更新了 源点到每一个点的权值 那么就只需要 n-1次循环得到

再换一种思考方式 如果 有两个集合 一个是最短路径的点集m 一个是非最短路径点集n 一个源点s 起始状态为m只有s 第一轮松弛 得出源点到其他点的距离 然后从n集合中 找到了 一个离a最短的点 然后松弛n
不断循环 下去 每次 m中会多一个节点 n中会少一个 一直到n为空结束 一共执行了 n次 这其中正是蕴含了 我们前面证明的那个定理

**Dijkstra**
时间复杂度 O(n*n)    n为节点数量
###核心代码:

```
for(int i=0;i<n;i++)
{
    int x,m=inf;
    *寻找从源点出发的一条最短路径 记录终点*
    for(int y=0;y<n;y++)
        if(!vis[y]&&d[y]<=m)
            m=d[x=y];
    *把即将松弛的中间点标记*
    vis[x]=1;
    *根据中间点来调整源点到每一个点的距离  如果经过源点到中间点再到终点的距离小于从从源点到终点*
    *则进行更新距离*
    for(int y=0;y<n;y++)
    d[y]=min(d[y],d[x]+map[x][y])
}
```

2 邻接表表示图

邻接表的构造方式为 firtst 和next 下都是存储的边 下图为图中的边

起点终点权值边号
1491号边
4382号边
1253号边
2464号边
1375号边

下表 为 邻接表

下标firstnext
15-1
24-1
3-11
42-1
53

对这个邻接表做一下解释 :
左边为起始边 然后右边为以起始边 开始的一系列边
例如如果要找 以一号点为起点的所有边的终点为 5 3 1

产生过程 :
先把first 存储的第一个终边 存放到 next 数组 然后 将 first数组 的值修改为 现在所在的边号
这样 就使得 现在所存的终边 即作为终边值又作为 查找下一个终边时候的索引 这样 就构成了一个终边链

感觉有些地方还是有些啰嗦 后续还会更新的

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值