Floyd算法:多源最短路径

简介

Floyd算法是一种用于求解加权图中任意两点之间的最短路径的算法。它是一种动态规划算法,通过不断迭代更新最短路径矩阵来求解所有最短路径。

特点

Floyd算法具有以下特点:

  • Floyd算法可以求解所有顶点之间的最短路径,而不仅仅是单源最短路径。
  • Floyd算法的时间复杂度为 O(n^3),其中 n 是图中顶点的个数。
  • Floyd算法的空间复杂度为 O(n^2)。

应用

Floyd算法在计算机科学中有着广泛的应用,包括:

  • 路由规划: Floyd算法可以用于计算网络中任意两点之间的最短路径。
  • 最短路径问题: Floyd算法可以用于解决各种最短路径问题,例如旅行商问题。
  • Floyd算法还可以用于解决图的连通性、最小生成树等问题。

实现

Floyd算法可以通过以下步骤实现:

  1. 初始化一个 n 阶方阵 D,其中 D[i][j] 表示从顶点 i 到顶点 j 的最短路径长度。

  2. 对所有顶点 i 和 j 进行迭代:

    • 如果 i 等于 j,则 D[i][j] 等于 0。
    • 否则,如果存在一条边直接连接顶点 i 和 j,则 D[i][j] 等于该边的权重。
    • 否则,D[i][j] 等于 D[i][k] + D[k][j] 的最小值,其中 k 是任意顶点。
  3. 迭代结束后,D[i][j] 表示从顶点 i 到顶点 j 的最短路径长度。

例题 P1364 医院设置

设有一棵二叉树,如图:

其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 11。如上图中,若医院建在 11 处,则距离和 =4+12+2×20+2×40=136=4+12+2×20+2×40=136;若医院建在 33 处,则距离和 =4×2+13+20+40=81=4×2+13+20+40=81。

输入格式

第一行一个整数 n,表示树的结点数。

接下来的 n 行每行描述了一个结点的状况,包含三个整数 w,u,v,其中 w 为居民人口数,u 为左链接(为 00 表示无链接),v 为右链接(为 00 表示无链接)。

输出格式

一个整数,表示最小距离和

分析:这题可以用Floyd算法将医院依次按在每个节点上,再得出最小距离和 一下是有详细注释的代码

#include <stdio.h>
#include <string.h>

#define big 100000007 // 定义一个大数,表示无穷大
int p[101], dis[101][101], sum; // 定义节点权重数组、距离数组和路径和变量
int n, l, r; // 定义节点数量、左右相邻节点

int main() {
    scanf("%d", &n); // 输入节点数量
    memset(dis, big, sizeof(dis)); // 初始化距离数组为一个很大的值,表示无穷大
    for (int i = 1; i <= n; i++) {
        dis[i][i] = 0; // 自己到自己的距离为0
        scanf("%d %d %d", &p[i], &l, &r); // 输入节点权重和相邻节点
        if (l >= 0) {
            dis[i][l] = 1; // 如果左相邻节点存在,则距离为1
            dis[l][i] = 1; // 双向路,需要设置另一条方向的距离
        }
        if (r >= 0) {
            dis[i][r] = 1; // 如果右相邻节点存在,则距离为1
            dis[r][i] = 1;
        }
    }
    // 使用 Floyd-Warshall 算法计算所有节点之间的最短路径
    for (int k = 1; k <= n; k++) { //中转结点
        for (int i = 1; i <= n; i++) {//起始起点
            if (i != k) {
                for (int j = 1; j <= n; j++) {//结束结点
                    if (i != j && k != j && dis[i][j] > dis[i][k] + dis[k][j]) {
                        dis[i][j] = dis[i][k] + dis[k][j]; // 更新最短路径
                    }
                }
            }
        }
    }
    int minn = big;
    // 计算每个节点到其他节点的路径和,找出最小的路径和
    for (int i = 1; i <= n; i++) {
        sum = 0;
        for (int j = 1; j <= n; j++) {
            if (i != j && dis[i][j] != big) {
                sum += p[j] * dis[i][j]; // 计算路径和
            }
        }
        if (minn > sum) {
            minn = sum; // 更新最小路径和
        }
    }
    printf("%d\n", minn); // 输出最小路径和
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值