1、Dijkstra算法

求一个顶点到其它所有顶点的最短路径,是一种按路径长度递增的次序产生最短路径的算法。

算法思想:

按路径长度递增次序产生算法:

把顶点集合V分成两组:

(1)S:已求出的顶点的集合(初始时只含有源点V0)

(2)V-S=T:尚未确定的顶点集合

将T中顶点按递增的次序加入到S中,保证:

(1)从源点V0到S中其他各顶点的长度都不大于从V0到T中任何顶点的最短路径长度

(2)每个顶点对应一个距离值

S中顶点:从V0到此顶点的长度

T中顶点:从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度

依据:可以证明V0到T中顶点Vk的,或是从V0到Vk的直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和

(反证法可证)

求最短路径步骤

算法步骤如下:

1. 初始时令 S={V0},T={其余顶点},T中顶点对应的距离值

若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值

若不存在<V0,Vi>,d(V0,Vi)为∞

2. 从T中选取一个其距离值为最小的顶点W且不在S中,加入S

3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值

重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止

2、Floyd算法

求所有顶点到所有顶点的最短路径。

算法思想:

1,从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。

2,对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。

把图用邻接矩阵G表示出来,如果从Vi到Vj有路可达,则G[i,j]=d,d表示该路的长度;否则G[i,j]=无穷大。定义一个矩阵D用来记录所插入点的信息,D[i,j]表示从Vi到Vj需要经过的点,初始化D[i,j]=j。把各个顶点插入图中,比较插点后的距离与原来的距离,G[i,j] = min( G[i,j], G[i,k]+G[k,j] ),如果G[i,j]的值变小,则D[i,j]=k。在G中包含有两点之间最短道路的信息,而在D中则包含了最短通路径的信息。

比如,要寻找从V5到V1的路径。根据D,假如D(5,1)=3则说明从V5到V1经过V3,路径为{V5,V3,V1},如果D(5,3)=3,说明V5与V3直接相连,如果D(3,1)=1,说明V3与V1直接相连。

优缺点:

Floyd算法适用于APSP(All Pairs Shortest Paths),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法。

优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单

缺点:时间复杂度比较高,不适合计算大量数据。

算法具体代码如下:

/* Graph.h头文件 */
/*包含图的建立:图的深度优先遍历、图的广度优先遍历*/
/*包含图的最小生成树:Prim 算法、Kruskal 算法*/
/*包含图的最短路径算法:Dijkstra算法、Floyd算法*/
#include<iostream>
#include"LinkQueue.h"
#define MAXVEX 100
#define MAXEDGE 100
#define INFINITY 65535
#define TRUE 1
#define FALSE 0
typedef char VertexType;
typedef int EdgeType;
typedef int Boolean;
typedef int Patharc[MAXVEX]; /*用于存储最短路径下标的数组*/
typedef int ShortPathTable[MAXVEX]; /*用于存储到各点最短路径的权值和*/
typedef int Pathmatrix[MAXVEX][MAXVEX];
typedef int ShortPathTable_Floyd[MAXVEX][MAXVEX]; using namespace std; /*邻接矩阵方式建立图*/
class MGraph{
public:
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVertexes,numEdges;
}; /*建立无向网图的邻接矩阵表示*/
void CreateMGraph(MGraph *G)
{
int i,j,k,w;
cout<<"输入顶点数和边数:"<<endl;
cin>>G->numVertexes>>G->numEdges;
cin.clear();
cout<<"输入顶点信息:"<<endl;
for(i=0;i<G->numVertexes;i++)
{
cin>>G->vexs[i];
cin.clear();
}
for(i=0;i<G->numVertexes;i++)
for(j=0;j<G->numVertexes;j++)
{
if (i==j)
G->arc[i][j]=0;
else
G->arc[i][j]=INFINITY;
}
for(k=0;k<G->numEdges;k++)
{
cout<<"输入边(vi,vj)上的下标i,下标j和权w:"<<endl;
cin>>i>>j>>w;
cin.clear();
G->arc[i][j]=w;
G->arc[j][i]=G->arc[i][j];
}
} /*邻接矩阵的深度优先递归算法*/
Boolean visited[MAXVEX]; /*访问标志的数组*/
void DFS(MGraph G,int i)
{
int j;
visited[i]=TRUE;
cout<<G.vexs[i]; /*打印顶点,也可以其他操作*/
for(j=0;j<G.numVertexes;j++)
if(G.arc[i][j]==1 && !visited[j])
DFS(G,j); /*对为访问的邻接顶点递归调用*/
}
/*邻接矩阵的深度优先遍历操作*/
void DFSTraverse(MGraph G)
{
cout<<"\n深度优先遍历结果为:"<<endl;
int i;
for(i=0;i<G.numVertexes;i++)
visited[i]=FALSE; /*初始化所有顶点状态都是未访问过状态*/
for(i=0;i<G.numVertexes;i++)
if(!visited[i]) /*对未访问过的顶点调用DFS,若是连通图,只会执行一次*/
DFS(G,i);
cout<<endl;
} /*邻接矩阵的广度遍历算法*/
void BFSTraverse(MGraph G)
{
cout<<"广度优先遍历结果为:"<<endl;
int i,j;
LinkQueue Q;
for(i=0;i<G.numVertexes;i++)
visited[i]=FALSE;
for(i=0;i<G.numVertexes;i++)
{
if(!visited[i])
{
visited[i]=TRUE;
cout<<G.vexs[i];
Q.EnQueue(i);
while(!Q.QueueEmpty())
{
Q.DeQueue(&i);
for(j=0;j<G.numVertexes;j++)
{
if(G.arc[i][j]==1 && !visited[j])
{
visited[j]=TRUE;
cout<<G.vexs[j];
Q.EnQueue(j);
}
}
}
}
}
cout<<endl;
} /* Prim算法生成最小生成树 */
void MiniSpanTree_Prim(MGraph G)
{
cout<<"Prim算法生成最小生成树,结果为:"<<endl;
int min,i,j,k;
int adjvex[MAXVEX];
int lowcost[MAXVEX];
lowcost[0]=0;
adjvex[0]=0;
for(i=1;i<G.numVertexes;i++)
{
lowcost[i]=G.arc[0][i];
adjvex[i]=0;
}
for(i=1;i<G.numVertexes;i++)
{
min=INFINITY;
j=1;k=0;
while(j<G.numVertexes)
{
if(lowcost[j]!=0 && lowcost[j]<min)
{
min=lowcost[j];
k=j;
}
j++;
}
cout<<"("<<adjvex[k]<<","<<k<<")"<<endl;
lowcost[k]=0;
for(j=1;j<G.numVertexes;j++)
{
if(lowcost[j]!=0 && G.arc[k][j]<lowcost[j])
{
lowcost[j]=G.arc[k][j];
adjvex[j]=k;
}
}
}
cout<<endl;
} /* Kruskal 算法生成最小生成树 */ class Edge{ /*对边集数组Edge结构的定义*/
public:
int begin;
int end;
int weight;
}; void Swap(Edge *edges,int i,int j) /* 交换权值 以及头和尾 */
{
int temp;
temp=edges[i].begin;
edges[i].begin=edges[j].begin;
edges[j].begin=temp;
temp=edges[i].end;
edges[i].end=edges[j].end;
edges[j].end=temp;
temp=edges[i].weight;
edges[i].weight=edges[j].weight;
edges[j].weight=temp;
} void sort(Edge edges[],MGraph *G) /* 对权值进行排序 */
{
int i,j;
for ( i=0;i<G->numEdges;i++)
{
for ( j=i+1;j<G->numEdges;j++)
{
if (edges[i].weight>edges[j].weight)
{
Swap(edges,i,j);
}
}
}
cout<<"权排序之后的为:"<<endl;
for (i=0;i<G->numEdges;i++)
{
cout<<"("<<edges[i].begin<<","<<edges[i].end<<")"<<endl;
}
} int Find(int *parent,int f) /*查找连线顶点的尾部下标*/
{
while (parent[f]>0)
f=parent[f];
return f;
} void MiniSpanTree_Kruskal(MGraph G)
{
int i,j,n,m;
Edge edges[MAXEDGE];
int parent[MAXVEX]; /*将邻接数组G转化为边集数组edges并按权由小到大排序*******BEGIN*********/
int k=0;
for ( i=0;i<G.numVertexes-1;i++)
{
for (j=i+1;j<G.numVertexes;j++)
{
if (G.arc[i][j]<INFINITY)
{
edges[k].begin=i;
edges[k].end =j;
edges[k].weight=G.arc[i][j];
k++;
}
}
}
sort(edges, &G);
/***************END***********************/ for (i=0;i<G.numVertexes;i++)
parent[i]=0; /* 初始化数组值为0 */
cout<<"Kruskal 算法生成最小生成树,结果为:"<<endl;
for (i=0;i<G.numEdges;i++) /* 循环每一条边 */
{
n=Find(parent,edges[i].begin);
m=Find(parent,edges[i].end);
if (n!=m) /* 假如n与m不等,说明此边没有与现有的生成树形成环路 */
{
parent[n]=m; /* 将此边的结尾顶点放入下标为起点的parent中。 */
/* 表示此顶点已经在生成树集合中 */
cout<<"("<<edges[i].begin<<","<<edges[i].end<<") "<<edges[i].weight<<endl;
}
}
} /* Dijkstra算法,求有向网G的V0顶点到其余顶点V最短路径P[V]及带权长度D[V]*/
/*P[V]的值为前驱顶点下标,D[V]表示V0到V的最短路径长度和*/
void ShortestPath_Dijkstra(MGraph G, int V0, Patharc *P, ShortPathTable *D)
{
int v,w,k,min;
int final[MAXVEX];
for(v = 0; v<G.numVertexes; v++)
{
final[v] = 0;
(*D)[v] = G.arc[V0][v];
(*P)[v] = V0;
}
(*D)[V0] = 0;
final[V0] = 1;
/*开始主循环,每次求得V0到某个V顶点的最短路径*/
for(v=0; v<V0; v++)
{
min = INFINITY;
for(w=0; w<G.numVertexes; w++)
{
if(!final[w] && (*D)[w]<min)
{
k = w;
min = (*D)[w];
}
}
final[k] = 1;
for (w=0; w<G.numVertexes; w++) /*修正当前最短路径及距离*/
{
if(!final[w] && (min+G.arc[k][w]<(*D)[w]))
{
(*D)[w] = min+G.arc[k][w];
(*P)[w] = k;
}
}
}
for(v=V0+1; v<G.numVertexes; v++)
{
min = INFINITY;
for(w=0; w<G.numVertexes; w++)
{
if(!final[w] && (*D)[w]<min)
{
k = w;
min = (*D)[w];
}
}
final[k] = 1;
for (w=0; w<G.numVertexes; w++) /*修正当前最短路径及距离*/
{
if(!final[w] && (min+G.arc[k][w]<(*D)[w]))
{
(*D)[w] = min+G.arc[k][w];
(*P)[w] = k;
}
}
} cout<<"V"<<V0<<"节点到其余个节点的最短路径为:"<<endl;
for (w=0; w<G.numVertexes; w++)
{
cout<<(*D)[w]<<" ";
}
cout<<endl;
cout<<"V"<<V0<<"节点到其余个节点的最短路径的前驱节点为:"<<endl;
for (w=0; w<G.numVertexes; w++)
{
cout<<"V"<<(*P)[w]<<" ";
}
cout<<endl;
}
/***********Dijkstra算法结束************/ /*Floyd算法,求网图G中各顶点V到其余顶点W最短路径P[V][W]及带权长度D[V][W]*/
void ShortestPath_Floyd(MGraph G, Pathmatrix *P, ShortPathTable_Floyd *D)
{
int v,w,k;
for(v=0; v<G.numVertexes; ++v) /*初始化D与P*/
{
for(w=0; w<G.numVertexes; ++w)
{
(*D)[v][w] = G.arc[v][w];
(*P)[v][w] = w;
}
}
for(k=0; k<G.numVertexes; ++k)
{
for(v=0; v<G.numVertexes; ++v)
{
for(w=0; w<G.numVertexes; ++w)
{
if ((*D)[v][w]>(*D)[v][k]+(*D)[k][w])
{
(*D)[v][w] = (*D)[v][k]+(*D)[k][w];
(*P)[v][w] = (*P)[v][k];
}
}
}
} for(v=0; v<G.numVertexes; ++v) /*输出显示最短路径*/
{
for(w=v+1; w<G.numVertexes; w++)
{
cout<<"V"<<v<<"-V"<<w<<"的最短距离为:"<<(*D)[v][w]<<endl;
k = (*P)[v][w];
cout<<"路径为:V"<<v;
while(k!=w)
{
cout<<" -> V"<<k;
k=(*P)[k][w];
}
cout<<" -> V"<<w<<endl;
}
cout<<endl;
}
}
/***********Floyd算法结束************/

对于如下的图:

代码运行结果如下:

两算法结果一致。

C++编程练习(11)----“图的最短路径问题“(Dijkstra算法、Floyd算法)的更多相关文章

  1. 图的最短路径:Dijkstra 和 Floyd

    //最短路径 /* dijkstra Dijkstra(迪杰斯特拉)算法的核心思想是贪心策略+动态规划 http://www.programgo.com/article/4721147659/ Dij ...

  2. 图的最短路径算法-- Floyd算法

    Floyd算法求的是图的任意两点之间的最短距离 下面是Floyd算法的代码实现模板: ; ; // maxv为最大顶点数 int n, m; // n 为顶点数,m为边数 int dis[maxv][ ...

  3. 数据结构(三十四)最短路径(Dijkstra、Floyd)

    一.最短路径的定义 在网图和非网图中,最短路径的含义是不同的.由于非网图没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径:而对于网图来说,最短路径是指两顶点之间经过的边上权值之 ...

  4. 最短路径Dijkstar算法和Floyd算法详解(c语言版)

    博客转载自:https://blog.csdn.net/crescent__moon/article/details/16986765 先说说Dijkstra吧,这种算法只能求单源最短路径,那么什么是 ...

  5. 多源最短路径算法—Floyd算法

    前言 在图论中,在寻路最短路径中除了Dijkstra算法以外,还有Floyd算法也是非常经典,然而两种算法还是有区别的,Floyd主要计算多源最短路径. 在单源正权值最短路径,我们会用Dijkstra ...

  6. [链接]最短路径的几种算法[迪杰斯特拉算法][Floyd算法]

    最短路径—Dijkstra算法和Floyd算法 http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html Dijkstra算 ...

  7. python数据结构与算法——图的最短路径(Dijkstra算法)

    # Dijkstra算法——通过边实现松弛 # 指定一个点到其他各顶点的路径——单源最短路径 # 初始化图参数 G = {1:{1:0, 2:1, 3:12}, 2:{2:0, 3:9, 4:3}, ...

  8. 模板 图的遍历 bfs+dfs 图的最短路径 Floyed+Dijkstra

    广搜 bfs //bfs #include<iostream> #include<cstdio> using namespace std; ],top=,end=; ][]; ...

  9. 最短路径(dijkstra 与 Floyd)

    目录 1. 如何建图? 2. Floyd 3. Dijkstra 1. 如何建图? 要跑最短路,首先要有图 --鲁迅 常用的存储方法有两种,分别是邻接矩阵(用二维数组表示边)和邻接表(模拟链表表示边) ...

随机推荐

  1. hadoop hdfs uri详解

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  2. SQL Server--导入和导出向导

    作用:创建一个只需要最少的转换就可以快速导入或导出数据的包 操作步骤: 1 打开打入和导出向导方式 有四种方式 1)在SSMS(SQL Server Management Studio)中,右击目标数 ...

  3. Redis状态和信息查看

    转自:http://my.oschina.net/tongyufu/blog/405612 redis-cli连接服务器后,使用info命令查看Redis信息和状态: INFO [section] 以 ...

  4. POJ 2395 Out of Hay

    这个问题等价于求最小生成树中权值最大的边. #include<cstdio> #include<cstring> #include<cmath> #include& ...

  5. poj3190区间类贪心+优先队列

    题意:每个奶牛产奶的时间为A到B,每个奶牛产奶时要占用一间房子,问n头奶牛产奶共需要多少房子,并输出每头奶牛用哪间房子 分析:这题就是一个裸的贪心,将奶牛按开始时间进行排序即可,但考虑一下数据范围,我 ...

  6. (中等) POJ 2528 Mayor's posters , 离散+线段树。

    Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral electio ...

  7. Masonry布局框架的使用

    Masonry是一个轻量级的布局框架 拥有自己的描述语法 采用更优雅的链式语法封装自动布局 简洁明了 并具有高可读性.比我们使用自动布局,繁琐的约束条件,好用多了.下面我们来学学masonry的使用方 ...

  8. HDU1429 bfs

    胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  9. 重拾python

    前一段碰到几次关于日期计算的题:给出一个日期,计算下一天的日期.虽然不限语言,可是我就C/C++还算熟悉,别的都是刚了解皮毛,根本不会用现成的库啊,无奈啊...只好用c语言一点点实现了,当时真是无比怀 ...

  10. 微信小程序之----生命周期

    在app.js的app()中注册程序 在页面.js中的Page({})中注册页面. 执行效果: