因为要做一道题牵扯到最小路径的算法,所以就看了看缔结斯特拉算法。
看了算法导论上面的介绍不明白,只好下了一个代码自己去看。
//单源图最短路径求法
int dijkstra(int from,int to ,int map[][N])
{
int *dis=new int[n];//源到n的距离
int *used=new int[n];//n点是否用过
int i,j,u,max=999999;
int mindis;
for(i=0;i<n;i++)
{
dis[i]=map[from][i];
used[i]=0;
}
used[from]=1;
while(!used[to])//目的地点已经加入后就停止.
{
mindis=max;
u=-1;
for(i=0;i<n;i++)
{
if(used[i]==0&&mindis>dis[i])
{
mindis=dis[i];
u=i;
}
}
s[u]=1;
for(i=0;i<n;i++)
{
if(s[i]==0)
{
if(dis[u]+masp[u][i]<dis[i])
dis[i]=dis[u]+map[u][i];
}
}
}
mindis=dis[to];
delete[] dis;
delete[] used;
return mindis;
}
看了之后自己总结的一点点的经验:
缔结斯特拉算法的步骤是这样的:
1.将点集分成两类,第一类是用过的一类是没有用过的。
2.在没有用过的点集中找到离远点距离最小的点。
3.将此点加入已用点的集合中,因为这个点的加入,源点和未用过的点的最短路径发生了变化。
4.重复上面的三项,直到终点被用了为止,即可得到源点到其他任意点的最短路径。
觉得这像是一种贪心,可是感觉又不是,因为在找最优的过程中,每个点的dis一直在变化.不知道为什么最小的路径的长度就出来了.觉得这好像是一个不可思议的事情.但求出来的确实是最短路径.让我们仔细的考虑一下这个算法的过程.当除了源点其余所有的点都没有用的时候,这些点离源点的距离就是图中真实的距离.找到最短的点放到已用的集合中,那么毋庸置疑源点到这个点的路径就定了下来就是源点直接到这个点的路径,并不需要经过其他的点来达到这个点.这是已用集合中就有了两个点,那么源点就可以经过这个点到达或不经过这个点到达其他的点(这里没有不可到达的点,不可到达的点就是路径比较长的点)。这其中做一个选择,看是经过这个点路径短一些还是不经过这个点路径短一些。所有的点做好选择后就可以形成一个新的数组,这个数组记录了源点到未用过的点的距离,同样选择一个最小的点加入到已用点中。就这样已用点集合中有了三个点,源点到其余两个点到距离已经确定。下面反复一下就可以得到源点到所有点的最短路径,线面的代码不仅可以求出路径的长度,亦可以求出路径的依次经过的点。
[4] 最短路径
(1)单源最短路径,dijkstra算法,邻接阵形式,复杂度O(n^2)
//求出源s到所有点的最短路经,传入图的顶点数n,(有向)邻接矩阵mat
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,但必须非负!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
void dijkstra(int n,elem_t mat[][MAXN],int s,elem_t* min,int* pre){
int v[MAXN],i,j,k;
for (i=0;i<n;i++)
min[i]=inf,v[i]=0,pre[i]=-1;
for (min[s]=0,j=0;j<n;j++){
for (k=-1,i=0;i<n;i++)
if (!v[i]&&(k==-1||min[i]<min[k]))
k=i;
for (v[k]=1,i=0;i<n;i++)
if (!v[i]&&min[k]+mat[k][i]<min[i])
min[i]=min[k]+mat[pre[i]=k][i];
}
}
pre[i]中存储了i点的上一个点是那个。求路径的话可以这样依次的找上一个点,知道找到源点结束即可。