最近学习离散数学里头的图论最短路,颇感兴趣,于是自己看了一下几种相关的算法,并且打算整理总结一下。
首先是单源最短路的dijkstra算法,是采取拓展点的方式来遍历更新指标函数,每个点都只拓展一次,而且根据算法的结构看,是双重循环,假设点的个数为n,复杂度为O(n2)
了解算法之前,我们先看一下数学定义,首先设顶点全集V,我们来求从v0到z的最短路。我们先将V分成两个集合,T和P,T={ v∈V| v0到v的最短路已经求出 },P=V-T还有对于任意的顶点t∈P,设l(t)表示从v0到t的最短路径和(在只经过T中顶点的前提下),若不存在这样的路径,l(t)=∞,我们称l(t)为t关于T的指标函数。
还是先把算法列出来吧:
⑴
开始时遍历P中每一个顶点t,初始化令l(t)=W(vo,t) W(x,y)表示从顶点x到顶点y的距离,如果x不能直接到y,则该值为∞
⑵找到最小点x,将x加入到T中,即T=T+{x}, P=P-{x}
⑶在拓展与x相邻的点的指标函数,因为此时满足从x走过来为最小值,如果l(t)>l(x)+W(x,t)那么修改一下l(t)=l(x)+W(x,t);
然后再继续从⑵循环知道T=V才停止
额,这里我还显示了一下路径,就是用一个string trace[i]来表示从v0 走到i的最短路径
具体c++描述如下
int Dijkstra(int startp,int endp)
{
int l[100];
bool P[100];
string trace[100];
for(int i=1;i<=vertex;++i)
{
l[i]=INF,P[i]=true;
}
l[startp]=0;
trace[startp].append(to_string(startp));
for(int i=1;i<=vertex;++i)
{
int x,min=INF;
for(int j=1;j<=vertex;++j)
{
if(P[j] && min>l[j])
{
min=l[j];
x=j;
}
}
P[x]=false;
for(int j=1;j<=vertex;++j)
{
if(matrix[x][j] && P[j] && l[j]>l[x]+matrix[x][j])
{
l[j]=l[x]+matrix[x][j];
trace[j].clear();
trace[j].append(trace[x]);
trace[j].append(to_string(j));
}
}
}
cout<<"dijkstra: trace=";
for(int i=0;i<trace[endp].size();++i)
{
if(!i)cout<<trace[endp][i];
else cout<<"->"<<trace[endp].at(i);
}
cout<<endl;
return l[endp];
}