图论------迪杰斯特拉(Dijkstra)算法求单源最短路径。

编程要求


在图的应用中,有一个很重要的需求:我们需要知道从某一个点开始,到其他所有点的最短路径。这其中,Dijkstra 算法是典型的最短路径算法。

本关的编程任务是补全右侧代码片段中 Begin 至 End 中间的代码,实现 Dijkstra 算法求单源最短路径,具体要求如下:

补全代码 int[] Paths(int source) 方法,实现 Dijkstra 算法;

输出源点 source 到其他各个定点的距离,如果不可达,则距离输出 INF。

测试举例
测试过程:

平台将创建用户补全后的ShortestPath类的对象;

调用对象的addEdge(int u, int v, int w)方法,添加边和边的权重信息,构建图G;

调用对象的Paths(int source)方法执行Dijkstra算法,求最短路径,并输出返回的最短路径,这里源点设置为1;

接着根据程序的输出判断程序是否正确。

以下是测试样例:

测试输入:

5 7
1 2 8
1 3 1
1 4 2
3 4 2
2 4 3
3 5 3
4 5 3
(5 和 7 分别表示顶点数和边数)

预期输出:

0 5 1 2 4 

思路解析:

        求单源最短路径就是求一个点到除它以外所有点的最短距离,首先我们还是用邻接矩阵来储存图的信息。以测试输入为例,示意图如下。


        既然是求1的单源最短路径,那我们就定义一个数组dic[n+1],将dic初始化存储从1到所有点的直接距离。比如dic[1]到dic[5]分别是【0,8,1,2,99999999】,因为1无法直接到5,所以初始化为99999999。

        然后找出dic里面1到2-n之间的最短距离,发现是dic[3] = 1,然后找1通过3能到达的地方,发现能到达4和5,如果1通过3到达4的话,得出dic[4] = 2 < dic[3]+arr[3][4] = 3,无法使到四的路程更短,所以不改变dic[4]的值,但是我们发现到达5,即dic[5] = 99999999>dic[3]+arr[3][5] = 4,能使1到5距离缩短,于是改变dic[5]的值。这样我们就得到能通过3进行优化一轮路径,学术名叫做松弛。

        


        我们知道,如果已经通过3实现了一轮优化,那么我们将进一步缩短路程的话,是不能走回头路的,因为如果再次经过3的话没有意义,所以最短路没有重复路径。

        那么我们就要定义一个数组来存储已经作为转点进行一轮松弛的点,我们可以定义book[n+1]来存储。将作为转点的点比如3,用book[3] = 1,表示已经使用过。

        之后便是重复步骤,找除去dic[3]以外的最小值,也就是dic[4],继续进行一轮松弛,将4这个点用book[4] = 1,表示已经使用过。

        之后的图大家可以自己试着来画出。

具体代码:

#include<stdio.h>

int main(void)

{

    int arr[100][100] = { 0 };

    int dic[100];

    int book[100] = { 0 };

    int m, n, a, b, c, u, v;

    int inf = 99999999;

    scanf("%d%d", &n, &m);

    for (int i = 1; i <= n; i++)

        for (int j = 1; j <= n; j++)

            if (i == j)

                arr[i][j] = 0;

            else

                arr[i][j] = inf;

    for (int i = 1; i <= m; i++)

    {

        scanf("%d%d%d", &a, &b, &c);

        arr[a][b] = c;

        arr[b][a] = c;

    }//无向图初始化。

    for (int i = 1; i <= n; i++)

        dic[i] = arr[1][i];//初始化dic数组


 

    for (int i = 1; i <= n - 1; i++)//最多要进行n-1轮松弛,i值不会使用,仅仅表示循环多少轮。

    {

        int min = inf;

        for (int j = 2; j <= n; j++)

        {

            if (book[j] == 0 && dic[j] < min)

            {

                min = dic[j];

                u = j;

            }

        }//找出从1到任意数字的最短值。

        book[u] = 1;//将该位置提前存储,表示已经使用过。

        for (v = 2; v <= n; v++)//优化1通过u到所有点的路径。

        {

            if (arr[u][v] < inf)//如果u到v没有通路,也就没办法优化。

            {

                if (dic[v] > dic[u] + arr[u][v])

                    dic[v] = dic[u] + arr[u][v];//优化赋值过程。

            }

        }

    }

    for (int i = 1; i <= n; i++)

        printf("%d ", dic[i]);//打印结果。

    return 0;

}

注意:

        实际上迪杰斯特拉算法可以看作是贪心算法,通过每一步的最优解组合成全局最优解,感兴趣的同学们可以去网上查找关于贪心算法的知识,这种类型的题目我们以后也会分享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值