图论:单源最短路与多源最短路问题

转载自http://acm.uestc.edu.cn/bbs/read.php?tid=5670

下载ppt帐号:qscqesze

密码:123456

-------------------------------------------------------------------

单源最短路径:

松弛操作:D[i]表示源点s到i的当前最短路径
1.条件:d[i]+e[i][j]<d[j]
2.更新:d[j]=d[i]+e[i][j]

Dijkstra算法:

算法初始时d[s] = 0,其余的点的d[]值为INF。有S、T两个集合,S集合中包含所有已求得最短路的点,T集合包含未求得最短路的点。
当T集合非空时,从T集合中选取d[]值最小的一个点,如果该点的d[] !=INF,则把它放入S集合,此时d[]值就是该点的最短路值。
当T集合为空或从T中选出的点的d[]==INF时,算法结束。

void dijkstra(int s,int t) {    初始化S={空集}, T=全集-S;    d[s] = 0; 其余d值为INF    while (T非空 && T中最小的d[] != INF)    {        取出T中具有最小d[]的点i;        for (所有不在S中且与i相邻的点j)          if (d[j] > d[i] + cost[i][j]) d[j] = d[i] + cost[i][j]; ( “松弛”操作” )        S = S + {i}; //把i点添加到集合S里        T = T – {i};    }    return;}

关于算法的说明:

每次选取的j使d[]最小,这样可以保证它的路径已经是最短路。因为如果经过某个未标记点p到达j会产生更短的路,那么到达j的最短路长度必然要加上一个更大的d [p],矛盾

d [k]=min{d [k],d [j]+cost[j][k]}的作用是在标记j以后更新d数组(松弛操作)

每次循环会对1个点进行标记,所以n-1次循环后所有点都做标记,d[]的含义变成可以经过所有点的最短距离,就是我们要的最短距离

如果找到的d[]最小的一个是d[]=无穷大,则可以提前结束循环,未做标记的点都是不可到达的

Dijkstra只能针对正权

所有边权非负
单源最短路
Dijkstra的本质是基于贪心的思想

反例:

Dijkstra复杂度:
最朴素的实现O(V^2)
堆实现O(ElogV)

Dijkstra堆实现:

用堆实现Dijkstra算法可以将复杂度降至O( ElogV);
用堆来维护T集合中的点,则在选取T集合中具有最小d[]值的点的复杂度为O(1),而每次在堆中维护一个点的复杂度为O(logV),每条边可能进行一次维护。所以总复杂度是O(ElogV);
当E<<V*V时,用堆实现将会快很多。

 SPFA算法(Shortest Path Faster Algorithm)

SPFA算法用队列来保存可能做松弛操作的节点。
初始时所有点d[]值置INF,源点d[s]为0。将源点放进队列。
当队列不为空时每次从队列中取出队首节点,对该节点发出的每条边进行松弛。将松弛后d[]值改变并且不在队列中的点加入队列。

void spfa(int s){
  for(int i = 1; i <= n; ++i) d[i] = INF; //所有点的d[]置无穷
       d[s] = 0;            // 源点d[]置0
       q.push(s);
    while(!q.empty()){
         int x = q.front(); q.pop();
         for all edge(x, y, w)
            if(d[y] > d[x] + w){
                d[y] = d[x] + w;
                if(y不在q中) {
                    q.push(y);
                }
            }
    }
}

示例;

全局最短路径

Floyd-warshell:

求所有点对的最短路径
DP
设d[i][j][k]表示从i到j的路径中,经过的点的编号不超过k的最短路。
边界条件d[i][j][0] = dis[i][j],d[i][i]=0,余下d[i][j]=INF;
转移方程:
d[i][j][k] = Min(d[i][j][k-1] , d[i][k][k-1] + d[k][j][k-1]) (k > 0 , 0 <= i , j <= n)
则dp[i][j][n]即为所求

for(k=1;k<=n;++k)
    for(i=1;i<=n;++i)
        for(j=1;j<=n;++j)
        if(d[i][j]>d[i][k]+d[k][j])
            d[i][j]=d[i][k]+d[k][j];

算法时间复杂度为O(n^3)
原程序实际上是这个DP的一个精巧的实现,省略了最后一维数组
因为在第k次进行更新时,只会用d[u][k], d[k][u]对别的 d[][]值进行更新,而d[u][k]和d[k][u]不会改变。

Floyd vs Spfa
 

时间: 2024-10-18 00:56:25

图论:单源最短路与多源最短路问题的相关文章

多源最短路Floyed——多源最短路(CODEVS1077)(可能Floyed模板)

题目描述 Description 已知n个点(n<=100),给你n*n的方阵,a[i,j]表示从第i个点到第j个点的直接距离. 现在有Q个询问,每个询问两个正整数,a和b,让你求a到b之间的最短路程. 满足a[i,j]=a[j,i]; 输入描述 Input Description 第一行一个正整数n,接下来n行每行n个正整数,满足a[i,i]=0,再一行一个Q,接下来Q行,每行两个正整数a和b. 输出描述 Output Description 一共Q行,每行一个整数. 样例输入 Sample

模板C++ 03图论算法 1最短路之单源最短路(SPFA)

3.1最短路之单源最短路(SPFA) 松弛:常听人说松弛,一直不懂,后来明白其实就是更新某点到源点最短距离. 邻接表:表示与一个点联通的所有路. 如果从一个点沿着某条路径出发,又回到了自己,而且所经过的边上的权和小于0, 就说这条路是一个负权回路. 回归正题,SPFA是bellman-ford的一种改进算法,由1994年西安交通大学段凡丁提出.它无法处理带有负环的图,判断方法:如果某个点进入队列的次数超过N次则存在负环. SPFA的两种写法,bfs和dfs,bfs判别负环不稳定,相当于限深度搜索

【算法系列学习】Dijkstra单源最短路 [kuangbin带你飞]专题四 最短路练习 A - Til the Cows Come Home

https://vjudge.net/contest/66569#problem/A http://blog.csdn.net/wangjian8006/article/details/7871889 邻接矩阵实现的单源最短路 1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 #include

Dijkstra算法 --- 单源最短路

Dijkstra算法适用于边权值为正的情况,可用于计算正权图上的单元最短路. 其伪代码如下: 设d[v0] = 0, 其他d[i] = INF 循环n次{ 在所有未标号的结点中,选取d值最小的结点x 给结点x加上永久标号 对于从x出发的所有边,执行松弛操作. } //松弛操作的伪代码如下: RELAX(u,v,w) if(u.d + w(u,v) < v.d){ v.d = w.d + w(u,v); pre[v] = u; } Dijkstra算法代码: /* Dijkstra 单源最短路算法

常见模板(欧拉筛素数,最小生成树,快排,并查集,单源最短路)

欧拉筛素数: #include<cstdio> #define maxn 10000000+10 using namespace std; int n,prime[5000001],num_prime=0,m; bool if_prime[maxn]; void euler(int limit) { for(int i=2;i<=limit;i++) { if(!if_prime[i]) prime[++num_prime]=i; for(int j=1;prime[j]*i<=l

利用分支限界法求解单源最短路(Dijkstra)问题

分支限界法定义:采用BFS算法,并使用剪枝函数的算法称为分支界限法. 分支限界法解释:按广度优先的原则,有选择的在其child中进行扩展,从而舍弃不含有最优解的分支,不断重复这一过程,直到找到答案或者判定无解. 分支界限法常常用到优先队列来选择最佳扩展节点,有时也会用到普通队列,以先进先出为原则来进行筛选. 单源最短路问题定义:给定有向图和起点,寻找到达所有点的最短路径. 单源最短路的分支限界法概述:首先把节点加入优先队列,之后不断地从队列中取出最优扩展点,观察其可抵达的所有目标节点,若当前路径

UVA 658 It&#39;s not a Bug, it&#39;s a Feature! (单源最短路,dijkstra+优先队列,变形,经典)

题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢.但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了:要打多久才能无bug?(同1补丁可重复打) 分析: n<=20,那么用位来表示bug的话有220=100万多一点.不用建图了,图实在太大了,用位图又不好玩.那么直接用隐式图搜索(在任意点,只要满足转移条件,任何状态都能转). 但是有没有可能每个状态都要搜1次啊?那可能是100万*100万啊,这样出题

单源最短路_SPFA_C++

当我们需要求一个点到其它所有点的最短路时,我们可以采用SPFA算法 代码特别好写,而且可以有环,但是不能有负权环,时间复杂度是O(α(n)n),n为边数,α(n)为n的反阿克曼函数,一般小于等于4 模板:http://www.cnblogs.com/hadilo/p/5934679.html 我感觉自己讲的不会很好,丢一个链接算了 算法详解:http://www.360doc.com/content/13/1208/22/14357424_335569176.shtml 伪代码是自己写的: 可以

HDU-4849 Wow! Such City! (单源最短路)

Problem Description Doge, tired of being a popular image on internet, is considering moving to another city for a new way of life. In his country there are N (2 ≤N≤ 1000) cities labeled 0 . . . N - 1. He is currently in city 0. Meanwhile, for each pa