一个点(源点)到其余各个顶点的最短路径。也叫做“单源最短路径”Dijkstra。
Dijkstra的主要思想:每次找到离源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径
用flag标示该点是否在离源点最近的集合中
算法步骤:
1.初始时,S只包含源点,即P={v},v的距离为0。U包含除v外的其他顶点,即:Q={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
2.从U中选取一个距离v最小的顶点k,把k,加入P中(该选定的距离就是v到k的最短路径长度)。
3.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
4.重复步骤2和3直到所有顶点都包含在P中
时间复杂度是O(N^2)。其中每次找到离1号顶点最近的顶点的时间复杂度是O(N),这里可以用“堆”来优化使降低到O(logN),
另外对于边数M少于N^2的稀疏图来说(M<<N^2的图称为稀疏图,而M较大的图称为稠密图),我们可以用邻接表来代替邻接矩阵存储,使得整个时间复杂度优化到O(N+M)logN。
输出结果: 输入为点数,边数,点-点,源点
Dijkstra的主要思想:每次找到离源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径
用flag标示该点是否在离源点最近的集合中
算法步骤:
1.初始时,S只包含源点,即P={v},v的距离为0。U包含除v外的其他顶点,即:Q={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
2.从U中选取一个距离v最小的顶点k,把k,加入P中(该选定的距离就是v到k的最短路径长度)。
3.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
4.重复步骤2和3直到所有顶点都包含在P中
时间复杂度是O(N^2)。其中每次找到离1号顶点最近的顶点的时间复杂度是O(N),这里可以用“堆”来优化使降低到O(logN),
另外对于边数M少于N^2的稀疏图来说(M<<N^2的图称为稀疏图,而M较大的图称为稠密图),我们可以用邻接表来代替邻接矩阵存储,使得整个时间复杂度优化到O(N+M)logN。
在最坏的情况下M就是N^2,这样的话(N+M)logN要比N^2还要大,但是大多数情况下并不会有那么多边,因此(M+N)logN要比N^2小很多。
按照步骤来实现
dis:0 1 12 + + +
先找第一个离1号点最近的点是2号点,然后选择2号点来进行扩展2-3,2-4得出1-3,1-4
dis:0 1 10 4 + +
再在剩下的3-6中选择离1号点最近的点是4号,以此内推。。。。。。
dis:0 1 8 4 17 19
#include<iostream>
using namespace std;
int main()
{
int edgs;
int points;
int dis[10];
int flag[10];
int infinity=9999999;
cin>>points>>edgs;
int edg[10][10];
for (int i=1;i<=points;i++)
{
for (int j=1;j<=points;j++)
{
if (i==j)
{
edg[i][j]=0;
}
else
{
edg[i][j]=infinity;
}
}
}
int point1,point2,quanzhi;
for (i=1;i<=edgs;i++)
{
cin>>point1>>point2>>quanzhi;
edg[point1][point2]=quanzhi;
}
for (i=1;i<=points;i++)
{
dis[i]=edg[1][i];
}
for (i=1;i<=points;i++)
{
flag[i]=0;
}
flag[1]=1;
int min,u;
for (i=1;i<=points-1;i++)//源点到源点不用比较,因次总的次数少一次
{
min=infinity;
for (int j=1;j<points;j++)
{
if (flag[j]==0&&dis[j]<min)//核心思想:依次比较出离源点最近的点
{
min=dis[j];
u=j;
}
}
flag[u]=1;
for (int v=1;v<=points;v++) //找出离源点最近的点后开始更新dis里面的源点到各个点的值是否最小
{
if (edg[u][v]<infinity)
{
if (dis[v]>dis[u]+edg[u][v])//dis[1][v] 主要是找出离源点最近点的出边来比较
{
dis[v]=dis[u]+edg[u][v];
}
}
}
}
for (i=1;i<=points;i++)
{
cout<<dis[i]<<" ";
}
cout<<endl;
}
输出结果:dis[1-6]到所有顶点的最短距离
带有路径输出的:
#include<iostream>
#include<stack>
using namespace std;
int main()
{
int edgs;
int points;
int dis[10];
int flag[10];
int infinity=9999999;
cin>>points>>edgs;
int start ,end;
cin>>start>>end;
int source;
cin>>source;
int edg[10][10];
int father[10];
for (int i=1;i<=points;i++)
{
father[i]=0;
for (int j=1;j<=points;j++)
{
if (i==j)
{
edg[i][j]=0;
}
else
{
edg[i][j]=infinity;
}
}
}
int point1,point2,quanzhi;
for (i=1;i<=edgs;i++)
{
cin>>point1>>point2>>quanzhi;
edg[point1][point2]=quanzhi;
father[point2]=point1;
}
for (i=1;i<=points;i++)
{
dis[i]=edg[source][i];//
}
for (i=1;i<=points;i++)
{
flag[i]=0;
}
flag[source]=1;
int min,u;
for (i=1;i<=points-1;i++)//源点到源点不用比较,因次总的次数少一次
{
min=infinity;
for (int j=1;j<points;j++)
{
if (flag[j]==0&&dis[j]<min)//核心思想:依次比较出离源点最近的点
{
min=dis[j];
u=j;
}
}
flag[u]=1;
for (int v=1;v<=points;v++) //找出离源点最近的点后开始更新dis里面的源点到各个点的值是否最小
{
if (edg[u][v]<infinity)
{
if (dis[v]>dis[u]+edg[u][v])//dis[1][v] 主要是找出离源点最近点的出边来比较
{
dis[v]=dis[u]+edg[u][v];
father[v]=u;
}
}
}
}
for (i=1;i<=points;i++)
{
cout<<dis[i]<<" ";
}
cout<<endl;
int tmp;
stack<int>si;
si.push(end);
while (start!=end)
{
tmp=father[end];
if (tmp==0)
{
cout<<"此路不通"<<endl;
return 0;
}
si.push(tmp);
end=tmp;
}
while(!si.empty())
{
cout<<si.top()<<" ";
si.pop();
}
cout<<endl;
}
输出结果: 输入为点数,边数,点-点,源点