数据结构之最短路径(迪杰斯特拉算法和弗洛伊德算法 )

1.

在带权有向图G中,给定一个源点v,求从v到G中的其余各顶点的最短路径问题,叫做单源点的最短路径问题。

在常用的单源点最短路径算法中,迪杰斯特拉算法是最为常用的一种,是一种按照路径长度递增的次序产生最短路径的算法。

单源点的最短路径问题:给定带权有向图G和源点v,求从v到G中其余各顶点的最短路径。

我们用一个例子来具体说明迪杰斯特拉算法的流程。

定义源点为 0,dist[i]为源点 0 到顶点 i 的最短路径。其过程描述如下:

步骤 dist[1] dist[2] dist[3] dist[4] 已找到的集合
第 1 步 8 1 2 +∞ {2}
第 2 步 8 × 2 4 {2, 3}
第 3 步 5 × × 4 {2, 3, 4}
第 4 步 5 × × × {2, 3, 4, 1}
第 5 步 × × × × {2, 3, 4, 1}

第 1 步:从源点 0 开始,找到与其邻接的点:1,2,3,更新dist[]数组,因 0 不与 4 邻接,故dist[4]为正无穷。在dist[]中找到最小值,其顶点为 2,即此时已找到 0 到 2 的最短路。

第 2 步:从 2 开始,继续更新dist[]数组:2 与 1 不邻接,不更新;2 与 3 邻接,因0→2→3比dist[3]大,故不更新dist[3] ;2 与 4 邻接,因0→2→4比dist[4]小,故更新dist[4]为 4。在dist[]中找到最小值,其顶点为 3,即此时又找到 0 到 3 的最短路。

第 3 步:从 3 开始,继续更新dist[]数组:3 与 1 邻接,因0→3→1比dist[1]小,更新dist[1]为 5;3 与 4 邻接,因0→3→4比dist[4]大,故不更新。在dist[]中找到最小值,其顶点为 4,即此时又找到 0 到 4 的最短路。

第 4 步:从 4 开始,继续更新dist[]数组:4 与 1 不邻接,不更新。在dist[]中找到最小值,其顶点为 1,即此时又找到 0 到 1 的最短路。

第 5 步:所有点都已找到,停止。

对于上述步骤,你可能存在以下的疑问:

若 A 作为源点,与其邻接的只有 B,C,D 三点,其dist[]最小时顶点为 C,即就可以确定A→C为 A 到 C 的最短路。但是我们存在疑问的是:是否还存在另一条路径使 A 到 C 的距离更小? 用反证法证明。

假设存在如上图的红色虚线路径,使A→D→C的距离更小,那么A→D作为A→D→C的子路径,其距离也比A→C小,这与前面所述 “dist[]最小时顶点为 C” 矛盾,故假设不成立。因此这个疑问不存在。

根据上面的证明,我们可以推断出,Dijkstra 每次循环都可以确定一个顶点的最短路径,故程序需要循环 n-1 次。

给你们说一下博主刚开始的问题:我做题时一直将最短路径数组置为0,结果他的值本来就是最小值,是所以输出也就是0.希望大家不要犯 博主的毛病。

不说了直接上题:其实迪杰斯特拉就是不停找最短距离的过程

数据结构之最短路径(迪杰斯特拉算法和弗洛伊德算法 )_第1张图片

输入

输入的第一行包含2个正整数n和s,表示图中共有n个顶点,且源点为s。其中n不超过50,s小于n。

以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。

输出

只有一行,共有n-1个整数,表示源点至其它每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。

请注意行尾输出换行。

样例输入

4 1
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0

样例输出

6 4 7 

完整代码展示

#include
using namespace std;
#define inf 10000
#define MAXSIZE 51
int Vis[MAXSIZE];
int map[MAXSIZE][MAXSIZE];
int Dis[MAXSIZE];
void Dijkstra(int n,int start){
  Vis[start]=1;
  for(int i=0;imap[index][i]+Dis[index]){
        Dis[i]=map[index][i]+Dis[index];
      }
    }
  }
}
int main(int argc, char const *argv[]) {
  int n,start;
  cin>>n>>start;
  for(int i=0;i>map[i][j];
    }
  }
  Dijkstra(n,start);
  for(int i=0;i

输出结果展示

数据结构之最短路径(迪杰斯特拉算法和弗洛伊德算法 )_第2张图片

2 佛洛依德算法

适用范围:1、单源最短路径(从源点到其他所有点v); 
2、有向图&无向图; 
3、边权可正可负 
4、差分约束系统 
图G(v,e),源点s,数组Distant[i]记录了从源点s到顶点i的路径长度,循环执行至多n-1次,n为顶点数。 
对每一条边e(u,v),如果Distant[u]+w[u,v]小于Distant[v],则Distant[v] = Distant[u]+w(u,v); 
每一次循环都会至少更新一个点,所以才会出现至多循环n-1次,一次更新是指用所有节点进行一次松弛操作,(为什么会出现循环一次都能至少确定一个节点的最短距离?) 
因为:1、将所有节点分为两类:已知最短距离的节点和剩余节点。 
2、这两类节点满足这样的性质:已知最短距离的节点的最短距离值都比剩余节点的最短路值小。 
3、易知到剩余节点的路径一定会经过已知节点。 
4、而从已知节点连到剩余节点的所以边中的最小的那个边,这条边所更新后的剩余节点就一定是确定的最短距离,从而多找到了一个能确定最短距离的节点(不用知道它是哪个节点)。

实现过程的三步:1、初始化所有的点,每一个点保存一个值,表示源点到这个点的距离其他点的值设为无穷大。 
2、进行循环,从1到n-1,进行松弛计算。 
3、遍历所有边,如果的d[v]大于d[u]+w(u,v)存在,则有从源点可达的权为负的回路。

做题:在带权有向图G中,求G中的任意一对顶点间的最短路径问题,也是十分常见的一种问题。

解决这个问题的一个方法是执行n次迪杰斯特拉算法,这样就可以求出每一对顶点间的最短路径,执行的时间复杂度为O(n3)。

而另一种算法是由弗洛伊德提出的,时间复杂度同样是O(n3),但算法的形式简单很多。zuotiaa

 算法描述

数据结构之最短路径(迪杰斯特拉算法和弗洛伊德算法 )_第3张图片

上题

输入

输入的第一行包含1个正整数n,表示图中共有n个顶点。其中n不超过50。

以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。

输出

共有n行,每行有n个整数,表示源点至每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。对于某个顶点到其本身的最短路径长度,输出0。

请在每个整数后输出一个空格,并请注意行尾输出换行。

样例输入

4
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0

样例输出

0 3 2 1 
6 0 4 7 
2 5 0 3 
3 6 1 0 

代码展示

#include
using namespace std;
#define MAXSIZE 51
#define inf 10000
//定义两个数组
int D[MAXSIZE][MAXSIZE];//最短路径
int P[MAXSIZE][MAXSIZE];//最短路径上的转折点
void Floyd(int d[MAXSIZE][MAXSIZE],int n){
  int v,w,k;
  for(v=0;vD[v][k]+D[k][w]){
          D[v][w]=D[v][k]+D[k][w];//更新功能
          P[v][w]=P[v][k];
        }
      }
    }
  }
}
int main(int argc, char const *argv[]) {
  int n;
  cin>>n;
  int d[MAXSIZE][MAXSIZE];
  for(int i=0;i>d[i][j];
    }
  }
  Floyd(d,n);
  for(int i=0;i

结果展示

数据结构之最短路径(迪杰斯特拉算法和弗洛伊德算法 )_第4张图片

博主文章写的简单,希望大家不要嫌弃。。。。。。。。。。。 

 

你可能感兴趣的:(数据结构与算法)