单源最短路径

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集合,全部放入则结束。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值