1、实验环境
Visual C++ 6.0
2、实验目的和要求
目的:给定一个带权有向图G=(V,E),其中每条边的权是一个实数。另外,还给定V中的一个顶点,称为源。现在要计算从源到其他所有各顶点的最短路径长度。这里的长度就是指路上各边权之和。
3、解题思路、伪代码
3.1解题思路:将一个图G中所有的顶点V分成两个顶点集合S和T。以v为源点已经确定了最短路径的终点并入S集合中,S初始时只含顶点v,T则是尚未确定到源点v最短路径的顶点集合。然后每次从T集合中选择S集合点中到T路径最短的那个点,并加入到集合S中,并把这个点从集合T删除。直到T集合为空为止。
具体步骤
1)选一顶点v为源点,并视从源点v出发的所有边为到各顶点的最短路径(确定数据结构:因为求的是最短路径,所以①就要用一个记录从源点v到其它各顶点的路径长度数组dist[],开始时,dist是源点v到顶点i的直接边长度,即dist中记录的是邻接阵的第v行。②设一个用来记录从源点到其它顶点的路径数组path[],path中存放路径上第i个顶点的前驱顶点)。
2)在上述的最短路径dist[]中选一条最短的,并将其终点(即
#include <stdlib.h>
#define M 100
#define N 100
#define INT_MAX 99999999
#define TRUE 1
#define FALSE 0
typedef struct node
{
int matrix[N][M]; //邻接矩阵
int n; //顶点数
int e; //边数
}MGraph;
void DijkstraPath(MGraph g,int *dist,int *path,int v0) //v0表示源顶点
{
int i,j,k;
int *visited=(int *)malloc(sizeof(int)*g.n); //n个点
for(i=0;i<g.n;i++){
if(g.matrix[v0][i]!=INT_MAX&&i!=v0){
dist[i]=g.matrix[v0][i];
path[i]=v0; //path记录最短路径上从v0到i的前一个顶点
}else{
path[i]=-1;
}
visited[i]=FALSE; //代表还没确定
}
path[v0]=v0;
dist[v0]=0;
visited[v0]=TRUE;
for(i=1;i<g.n;i++) //循环扩展n-1次
{
int min=INT_MAX;
int u;
for(j=0;j<g.n;j++) //寻找未被扩展的权值最小的顶点
{
if(visited[j]==FALSE&&dist[j]<min) //这个min是个循环,循环出最小的
{
min=dist[j];
u=j;
}
}
visited[u]=TRUE; //顶点u加入s集
for(k=0;k<g.n;k++) //更新dist数组的值和路径的值
{
if(visited[k]==FALSE&&min+g.matrix[u][k]<dist[k])
{
dist[k]=min+g.matrix[u][k];
path[k]=u;
}
}
}
}
void main(){
int n,e; //表示输入的顶点数和边数
printf("输入顶点数和边数:");
scanf("%d %d",&n,&e);
if(e!=0){
int i,j;
int s,t,w; //表示存在一条边s->t,权值为w
MGraph g;
int v0;
int *dist=(int *)malloc(sizeof(int)*n);
int *path=(int *)malloc(sizeof(int)*n);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
g.matrix[i][j]=INT_MAX; //默认是最大值
g.n=n;
g.e=e;
printf("输入权值(先输入两点,在输入两点之间的边):");
for(i=0;i<e;i++) //给矩阵赋值
{
scanf("%d %d %d",&s,&t,&w);
g.matrix[s][t]=w;
}
printf("输入源点:");
scanf("%d",&v0);
DijkstraPath(g,dist,path,v0);
printf("--------------------------------------\n");
/*设置输出*/
for(i=0;i<=n;i++){
if(i!=v0 && dist[i]<INT_MAX) /*源点到源点;源点到某点最长路径为无穷大的都不需要输出*/
{printf("\n从 %d 到 %d,最短路径 %d \n%d",v0,i,dist[i],i);
j=i;
do{ j=path[j];
printf("<---%d",j);
} while(j!=v0); /*输出直到前一个结点为源点为止,倒序输出*/
}
} printf("\n");
}
}
4、实验步骤
4.1输入:输入带权图:顶点,边数,图中的带权边。如图:
输出:
5、总结
单源最短路径问题采用Dijkstra算法,以最短路径长度递增,逐次生成最短路径的算法。把图中的点分成两个集合,一个是确定的最短路径的终点的集合S,一个是未确定的V-S集合,通过逐次生成最短路径,把顶点放入S集合,全部放入则结束。