【数据结构】基于Floyd算法的最短路径求解

【实验目的】

1.掌握图的邻接矩阵表示法。

2.掌握求解最短路径的Floyd算法。

【实验内容】

1、问题描述

一张地图包括n个城市,假设城市间有m条路径(有向图),每条路径的长 度已知。利用Floyd算法求出各个城市之间的最短路径。

2、输入要求

多组数据,每组数据有m+3行。第一行为两个整数n和m,分别代表城市 个数n和路径条数m。第二行有n个字符,代表每个城市的编号。第三行到第 m+2行每行有两个字符a和b和一个整数d,代表从城市a到城市b有一条距 离为d的路。当n和m都等于0时,输入结束。

3、输出要求

第1行开始打印记录城市vi和vj之间的最短路径长度的二维数组,即D[i][j]。 第2行开始打印最短路径上城市vj的前一城市编号的二维数组,即 Path[i][j]。

输入样例:

复制代码
4 8
0 1 2 3
0 1 5
0 3 7
1 2 4
1 3 2
2 0 3
2 1 3
2 3 2
3 2 1
0 0

输出样例:

复制代码
0 5 8 7 
6 0 3 2 
3 3 0 2 
4 4 1 0 

C++代码如下:

cpp 复制代码
#include<iostream> 
using namespace std;
#define MaxInt 32767  //表示极大值 
#define MVNum 100  //最大顶点数 
typedef char VerTexType;   //设置顶点类型为字符型 
typedef int ArcType;    //设置权重为整型 
typedef struct
{
	VerTexType vexs[MVNum];    //顶点表 
	ArcType arcs[MVNum][MVNum];   //邻接矩阵 
	int vexnum, arcnum;  //顶点数和边数 
}AMGraph;
//从顶点表中查找顶点
int LocateVex(AMGraph G, VerTexType u);
//构造有向网
int CreateDN(AMGraph& G);
// 佛洛依德算法的实现
void floydWarshall(AMGraph G);
int main()
{
	while (1)
	{
		AMGraph G;
		CreateDN(G);
		if (G.vexnum == 0 && G.arcnum == 0)
		{
			break;
		}
		floydWarshall(G);
	}
	return 0;
}
//从顶点表中查找顶点
int LocateVex(AMGraph G, VerTexType u)
{
	int i;
	for (i = 0;i < G.vexnum;i++)
	{
		if (u == G.vexs[i])
		{
			return i;
		}
	}
	return -1;
}
int CreateDN(AMGraph& G) 
{
	int i, j, k;
	cin >> G.vexnum >> G.arcnum;
	for (i = 0;i < G.vexnum;i++)
	{
		cin >> G.vexs[i];
	}
	for (i = 0;i < G.vexnum;i++)
	{
		for (j = 0;j < G.vexnum;j++)
		{
			G.arcs[i][j] = MaxInt;
		}
	}
	for (k = 0;k < G.arcnum;k++)
	{
		VerTexType v1, v2;
		ArcType w;
		cin >> v1 >> v2 >> w;
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		G.arcs[i][j] = w;
	}
	return 1;
}
void floydWarshall(AMGraph G) 
{
	// 初始化最短路径矩阵
	int dist[MVNum][MVNum], i, j, k;
	for (i = 0; i < G.vexnum; i++)
	{
		for (int j = 0; j < G.vexnum; j++)
		{
			dist[i][j] = G.arcs[i][j];
		}
	}
	// 更新最短路径矩阵
	for (k = 0; k < G.vexnum; k++) 
	{
		for (i = 0; i < G.vexnum; i++)
		{
			for (j = 0; j < G.vexnum; j++) 
			{
				if (dist[i][k] != MaxInt && dist[k][j] != MaxInt &&dist[i][k] + dist[k][j] < dist[i][j]) 
				{
					dist[i][j] = dist[i][k] + dist[k][j];
				}
			}
		}
	}
	for (i = 0;i < G.vexnum;i++)
	{
		for (j = 0;j < G.vexnum;j++)
		{
			if (i == j)
			{
				dist[i][j] = 0;
			}
			if (dist[i][j] != MaxInt)
			{
				cout << dist[i][j] << " ";
			}
			else
			{
				cout << "∞" << " ";
			}
		}
		cout << endl;
	}
	
}

Python代码如下:

python 复制代码
class AMGraph:
    def __init__(self):
        self.vexs = [''] * MVNum  # 顶点表,存储顶点字符
        self.arcs = [[MaxInt for _ in range(MVNum)] for _ in range(MVNum)]  # 邻接矩阵,存储边权
        self.vexnum = 0  # 实际顶点数量
        self.arcnum = 0  # 实际边数量

MaxInt = 32767  # 表示极大值(不可达)
MVNum = 100     # 最大顶点数

# 从顶点表中查找顶点对应的索引,未找到返回-1
def LocateVex(G, u):
    for i in range(G.vexnum):
        if G.vexs[i] == u:
            return i
    return -1

# 构造有向网(读取输入初始化图结构,适配"一行内空格分隔"的输入格式)
def CreateDN(G):
    # 读取顶点数和边数
    vexnum, arcnum = map(int, input().split())
    G.vexnum = vexnum
    G.arcnum = arcnum
    if G.vexnum == 0 and G.arcnum == 0:
        return 0  # 输入"0 0"时退出循环
    
    # 读取一行内的所有顶点(空格分隔,如"0 1 2 3")
    vertices = input().split()
    for i in range(G.vexnum):
        G.vexs[i] = vertices[i]
    
    # 初始化邻接矩阵为"极大值"(表示初始不可达)
    for i in range(G.vexnum):
        for j in range(G.vexnum):
            G.arcs[i][j] = MaxInt
    
    # 读取每条边的信息(一行内空格分隔,如"0 1 5")
    for k in range(G.arcnum):
        v1, v2, w = input().split()
        w = int(w)
        i = LocateVex(G, v1)
        j = LocateVex(G, v2)
        G.arcs[i][j] = w
    return 1

# Floyd-Warshall算法:求解所有顶点对之间的最短路径
def floydWarshall(G):
    # 初始化距离矩阵(复制邻接矩阵的初始值)
    dist = [[0 for _ in range(G.vexnum)] for _ in range(G.vexnum)]
    for i in range(G.vexnum):
        for j in range(G.vexnum):
            dist[i][j] = G.arcs[i][j]
    
    # 核心:通过中间顶点k,更新所有顶点对的最短路径
    for k in range(G.vexnum):
        for i in range(G.vexnum):
            for j in range(G.vexnum):
                # 若i→k和k→j都可达,且经过k的路径更短,则更新
                if dist[i][k] != MaxInt and dist[k][j] != MaxInt and dist[i][k] + dist[k][j] < dist[i][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]
    
    # 输出结果(处理自身到自身、不可达的情况)
    for i in range(G.vexnum):
        row = []
        for j in range(G.vexnum):
            if i == j:
                val = 0
            elif dist[i][j] != MaxInt:
                val = dist[i][j]
            else:
                val = "∞"  # 不可达用∞表示
            row.append(str(val))
        print(" ".join(row))

def main():
    while True:
        G = AMGraph()
        if CreateDN(G) == 0:  # 输入"0 0"时退出循环
            break
        floydWarshall(G)

if __name__ == "__main__":
    main()

Java代码如下:

java 复制代码
import java.util.Scanner;

public class FloydWarshall {
    static final int MaxInt = 32767; // 表示极大值(不可达)
    static final int MVNum = 100;    // 最大顶点数

    // 图的结构类,对应C++的AMGraph结构体
    static class AMGraph {
        char[] vexs = new char[MVNum];    // 顶点表,存储顶点字符
        int[][] arcs = new int[MVNum][MVNum]; // 邻接矩阵,存储边的权值
        int vexnum, arcnum;  // 实际顶点数和边数
    }

    // 从顶点表中查找顶点对应的索引,未找到返回-1
    static int LocateVex(AMGraph G, char u) {
        for (int i = 0; i < G.vexnum; i++) {
            if (G.vexs[i] == u) {
                return i;
            }
        }
        return -1;
    }

    // 构造有向网(读取输入初始化图,适配"一行内空格分隔"的输入格式)
    static int CreateDN(AMGraph G, Scanner scanner) {
        G.vexnum = scanner.nextInt();
        G.arcnum = scanner.nextInt();
        scanner.nextLine(); // 消耗当前行的剩余换行符,避免影响后续整行读取

        if (G.vexnum == 0 && G.arcnum == 0) {
            return 0; // 输入"0 0"时退出循环
        }

        // 读取一行内的所有顶点(空格分隔,如"A B C")
        String[] vertices = scanner.nextLine().split(" ");
        for (int i = 0; i < G.vexnum; i++) {
            G.vexs[i] = vertices[i].charAt(0);
        }

        // 初始化邻接矩阵为"极大值"(表示初始不可达)
        for (int i = 0; i < G.vexnum; i++) {
            for (int j = 0; j < G.vexnum; j++) {
                G.arcs[i][j] = MaxInt;
            }
        }

        // 读取每条边的信息(一行内空格分隔,如"A B 5")
        for (int k = 0; k < G.arcnum; k++) {
            String[] edgeParts = scanner.nextLine().split(" ");
            char v1 = edgeParts[0].charAt(0);
            char v2 = edgeParts[1].charAt(0);
            int w = Integer.parseInt(edgeParts[2]);

            int i = LocateVex(G, v1);
            int j = LocateVex(G, v2);
            G.arcs[i][j] = w;
        }
        return 1;
    }

    // Floyd-Warshall算法:求解所有顶点对之间的最短路径
    static void floydWarshall(AMGraph G) {
        // 初始化距离矩阵(复制邻接矩阵的初始值)
        int[][] dist = new int[G.vexnum][G.vexnum];
        for (int i = 0; i < G.vexnum; i++) {
            for (int j = 0; j < G.vexnum; j++) {
                dist[i][j] = G.arcs[i][j];
            }
        }

        // 核心逻辑:通过中间顶点k,更新所有顶点对的最短路径
        for (int k = 0; k < G.vexnum; k++) {
            for (int i = 0; i < G.vexnum; i++) {
                for (int j = 0; j < G.vexnum; j++) {
                    // 若i→k和k→j都可达,且经过k的路径更短,则更新i→j的距离
                    if (dist[i][k] != MaxInt && dist[k][j] != MaxInt && dist[i][k] + dist[k][j] < dist[i][j]) {
                        dist[i][j] = dist[i][k] + dist[k][j];
                    }
                }
            }
        }

        // 输出结果(处理"自身到自身"和"不可达"的情况)
        for (int i = 0; i < G.vexnum; i++) {
            for (int j = 0; j < G.vexnum; j++) {
                if (i == j) {
                    System.out.print("0 ");
                } else if (dist[i][j] != MaxInt) {
                    System.out.print(dist[i][j] + " ");
                } else {
                    System.out.print("∞ ");
                }
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        while (true) {
            AMGraph G = new AMGraph();
            if (CreateDN(G, scanner) == 0) { // 输入"0 0"时退出循环
                break;
            }
            floydWarshall(G);
        }

        scanner.close();
    }
}

总结

本文介绍了使用Floyd算法求解有向图最短路径的实现方法。通过邻接矩阵表示图结构,算法采用三重循环动态更新各顶点间的最短距离。实验内容包括:

(1)输入城市编号和路径信息;

(2)初始化邻接矩阵;

(3)执行Floyd算法核心步骤;

(4)输出最短路径矩阵。

提供了C++、Python和Java三种实现代码,均包含图结构定义、顶点定位、邻接矩阵构建和Floyd算法实现等模块。当输入城市数和路径数均为0时程序终止。

相关推荐
ERROR_LESS3 小时前
【ADS-1】【python基础-2】基本语法与数据结构(列表、字典、集合)
python
Camel卡蒙3 小时前
数据结构——二叉搜索树Binary Search Tree(介绍、Java实现增删查改、中序遍历等)
java·开发语言·数据结构
立志成为大牛的小牛3 小时前
数据结构——二十三、并查集的终极优化(王道408)
开发语言·数据结构·笔记·学习·程序人生·考研
一晌小贪欢4 小时前
Python爬虫第6课:Selenium自动化浏览器与动态内容抓取
爬虫·python·selenium·网络爬虫·python基础·python3·pathon爬虫
珊珊而川4 小时前
SAUP 算法
算法
.YM.Z4 小时前
数据结构——链表(二)
数据结构·链表
珹洺4 小时前
Java-Spring入门指南(二十七)Android Studio 第一个项目搭建与手机页面模拟器运行
java·spring·android studio
寂静山林4 小时前
UVa 1471 Defense Lines
算法
程序猿DD4 小时前
Java 25 中的 6 个新特性解读
java·后端