贪心法之最短路径之Dijkstra算法

A,问题描述:假如A地为仓库,要向不同的售货点供货,为了节约成本,因此要计算出从A点出发通向每个售货点的最短距离路径。也就是求解图中顶点A到图中其它各顶点的最短路径,图中每个顶点代表一个售货点。Dijkstra算法就是用于求解带权有向图中从一点出发到其它各顶点的最短路径的算法。下面详细介绍该算法。
B,Dijkstra算法:该算法用于求解从一个顶点出发到其余各顶点的最短路径的算法解决的是有向图中最短路径的问题,其主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。贪心法思想体现在每次优先选取离出发点O距离最近的点,然后再更改O点到其它各顶点的距离。
C,算法处理过程:
1)假设带权有向图G的顶点集合为V,起始点为V0;
2)初始S={V0},T=V-S={其余顶点},其中集合S表示已经计算出最短距离的顶点,T是还没计算的剩余顶点;
3)初始化V0到其余各点的距离,d(v0,vi)代表v0到vi的最短距离,按如下规则:即;
4)若V0可以直接到达某个顶点vi,则将边的权值赋给d(v0,vi),否则d(v0,vi)=∞;
5)从T中选取一个与S中顶点有关联(直接相连)且权值最小的顶点w(这里用到了贪心法思想),加入到S中;
6)以w作为中间点,若V0到T中某个顶点vi距离变短,则修改d(v0,vi)的值;
7)重复5)和6)直到T为空,即计算完了所有顶点,算法结束。
下图为Dijkstra算法求解最短路径的过程举例:
贪心法之最短路径之Dijkstra算法

D,算法实现:
#include"iostream"
usingnamespace std;
#defineMAXVEX 50//图中最大节点数
#defineMAXIMUN 65535//定义为最大数
typedefstruct //定义邻接矩阵的数据结构
{
charvexs[MAXVEX];
intedges[MAXVEX][MAXVEX];
int vexNum,adgeNum;//分别表示图中节点个数和边的条数
}AGraph;
intmain()
{
voidcreateG(AGraph *);
voidprintPath(AGraph *, int[], int);
voiddijkstra(AGraph *, int, int[], int[][MAXVEX]);
intd[MAXVEX][MAXVEX], prior[MAXVEX];
for(int i =0; i < MAXVEX; ++i)
prior[i] =-1;
AGraphg;
createG(&g);
//初始化d
for(int m =0; m < g.vexNum; ++m)
for(int n =0; n < g.vexNum; ++n)
{
d[m][n] =MAXIMUN;
}
intstart;
cout<<"请输入起始点start:";
cin>>start;
dijkstra(&g, start, prior, d);
while(true)
{
intnode;
cout<<"\n请输入顶点"<<start<<"所要到达的顶点i:";
cin>>node;
printPath(&g, prior, node);
cout<<g.vexs[node]<<endl;
cout<<"路径总长度为:"<<d[start][node]<<endl;
}
return0;
}
//输出到某个顶点node的路径
voidprintPath(AGraph *g, int prior[], int node)
{
intstack[MAXVEX], bottom, top;
top = bottom= -1;
while(prior[node] != -1)
{
stack[++top]= prior[node];
node =prior[node];
}
intpath;
while(top> bottom)
{
path =stack[top--];
cout<<g->vexs[path]<<"->";
}
}
//Dijkstra算法求解最短路径
//g为带权有向图,start为起始点
//prior保存从start到vi的路径中vi的前一个节点的下标
//d存放start到其余各顶点的最短路径值
voiddijkstra(AGraph *g, int start, int prior[], intd[][MAXVEX])
{
intS[MAXVEX], T[MAXVEX];//S为已经计算的顶点集合,T是剩余的顶点集合
int n =0;//表示已加入的顶点个数
//初始化d,S和T
for(int i =0; i < g->vexNum; ++i)
{
T[i] =i;//保存图中个顶点编号
//将与start直接相连的边的权值赋给d
if(g->edges[start][i] < MAXIMUN)
{
d[start][i] =g->edges[start][i];
prior[i] =start;
}
}
d[start][start] = 0;//修改起始顶点到它自身的距离为0
S[0] =start;//将start加入集合S
++n;
T[start] =-1;//将start从集合T中去掉,这里设置该位置为-1表示去掉
for(int j =1; j < g->vexNum; ++j)
{
int indexK,indexP, mintemp;//
//下面用贪心法思想寻找最优加入顶点
mintemp =MAXIMUN;
for(int p =0; p < n; ++p)
{
for(int k =0; k < g->vexNum; ++k)
{
if((T[k] !=-1) && (g->edges[S[p]][T[k]] < MAXIMUN) &&(mintemp > g->edges[S[p]][T[k]]))
{
mintemp =g->edges[S[p]][T[k]];
indexP =S[p];
indexK =T[k];
}
}
}
S[n++] =indexK;
T[indexK] =-1;
if(d[start][indexK] > (d[start][indexP] +g->edges[indexP][indexK]))
d[start][indexK] = d[start][indexP] +g->edges[indexP][indexK];//修改start与新加入的顶点的距离
//以indexK作为中间顶点修改start到剩余顶点的距离
for(int q =0; q < g->vexNum; ++q)
if((T[q] !=-1) && (g->edges[start][q] >g->edges[start][indexK] + g->edges[indexK][q]))
{
d[start][q] =g->edges[start][indexK] + g->edges[indexK][q];
prior[q] =indexK;
}
}
}
voidcreateG(AGraph *g)//创建无向网
{
int vNum,aNum;//分别代表要创建的图的节点数和边数
int start,end;//start->end表示节点start和end之间有一条边
intweight;//边的权重
cout<<"请输入图中节点的个数和边的条数:";
cin>>vNum>>aNum;
printf("\n请输入%d个节点的信息:", vNum);
//创建节点
for(int i =0; i < vNum; ++i)
{
cin>>g->vexs[i];
}
cout<<"这里输出节点编号及其存储的节点信息"<<endl;
for(int k =0; k < vNum; ++k)
cout<<k<<":"<<g->vexs[k]<<"";
cout<<endl;
//初始化无向图的边信息
for(int m =0; m < vNum; ++m)
for(int n =0; n < vNum; ++n)
{
g->edges[m][n] = MAXIMUN;
}
//创建无向图的边信息
for(int j =0; j < aNum; ++j)
{
cout<<"\n请输入第"<<j+1<<"条边的start和end节点和边的权重weight:";
cin>>start>>end>>weight;
g->edges[start][end] = weight;
g->edges[end][start] = weight;
}
//初始化vexNum和adgeNum
g->vexNum= vNum;
g->adgeNum= aNum;
}
运行结果:
贪心法之最短路径之Dijkstra算法

E,复杂度分析
时间复杂度:我们分析dijkstra()方法的时间复杂度,算法需要计算从start出发到其余各顶点的最短距离,需要n次,而每次查找最优加入顶点用了两层循环,所以上述实现时间复杂度为O(n^3)。
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值