当前位置: 首页 > news >正文

【数据结构】最长的最短路径的求解

任务描述

设计一个算法,求图G中距离顶点v的最短路径长度最大的一个顶点。

编程要求

输入

多组数据,每组数据m+2行。每组数据第一行为两个整数n和m,代表有n个顶点m条路。顶点编号为1到n。第二行到第m+1行每行有三个整数a,b和c,代表顶点a和顶点b之间有一条长度为c的路。第m+2有一个整数v,代表顶点v。当n和m都等于0时,输入结束。

输出

每组数据输出两行。第一行为最短路径最长的顶点编号c,第二行为两点的最短距离d。

测试说明

平台会对你编写的代码进行测试:

输入样例:

在这里给出一组输入。例如:

4 4
1 2 1
2 3 1
3 4 1
2 4 1
4
4 3
1 2 3
2 3 2
2 4 6
3
0 0

输出样例:

在这里给出相应的输出。例如:

1
2
4
8

整体实现流程

1.整体结构与核心功能

代码主要包含 3 个部分:

  1. 数据结构定义:用邻接矩阵存储无向图;
  2. 图的构建:通过输入初始化邻接矩阵;
  3. 最短路径求解:用 Dijkstra 算法计算源点到所有顶点的最短路径,最终输出最远顶点及其距离。

2.数据结构与宏定义

1. 宏定义
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100     // 最大顶点数(图的顶点上限)
#define MaxInt 10000  // 表示“无穷大”(用于初始化未直接相连的顶点距离)
2. 图的结构体定义
typedef char VerTexType;   // 顶点类型(此处未实际使用,代码中顶点用索引表示)
typedef int ArcType;       // 边的权重类型(整型)
typedef struct {ArcType arcs[MVNum][MVNum];  // 邻接矩阵:arcs[i][j]表示顶点i到j的权重int vexnum, arcnum;          // 图的顶点数和边数
} MGraph;

3.图的构建(CreateGraph函数)

功能:根据输入的顶点数、边数及边的信息,初始化邻接矩阵,构建无向图。

实现步骤:
  1. 初始化邻接矩阵

    • 对角线元素(顶点到自身的距离)设为 0;
    • 非对角线元素(顶点间无直接边)初始化为MaxInt(无穷大)。
  2. 读取边信息并更新矩阵

    • 输入每条边的起点s、终点e、权重w(注意:输入的顶点是 1-based 索引,代码中转换为 0-based);
    • 由于是无向图,边是双向的,因此同时更新arcs[s-1][e-1]arcs[e-1][s-1]w

4.Dijkstra 算法实现(ShortestPath_DIJ函数)

Dijkstra 算法用于求解带非负权重的图中,从源点到其他所有顶点的最短路径。核心思想是:通过逐步将 “距离源点最近的未访问顶点” 加入 “已确定最短路径的集合”,并更新其他顶点的距离。

1. 核心变量说明
  • final[v]:布尔数组,标记顶点v是否已加入 “已确定最短路径的集合”(true表示已加入);
  • D[v]:数组,存储源点v0到顶点v的当前最短距离;
  • p[v][w]:二维数组,记录源点到顶点v的最短路径经过的顶点(p[v][i]表示路径上的第i+1个顶点,-1表示路径结束)。
2. 算法步骤(详细流程)
(1)初始化
for (v = 0; v < G.vexnum; v++) {final[v] = false;                  // 所有顶点初始均未加入“已确定集合”D[v] = G.arcs[v0][v];              // 初始化源点到各顶点的距离(直接边的权重)for (w = 0; w < G.vexnum; w++) p[v][w] = -1;  // 路径数组初始化为-1(无路径)if (D[v] < MaxInt) {               // 若源点到v有直接边p[v][0] = v0;                  // 路径第一个顶点是源点v0p[v][1] = v;                   // 路径第二个顶点是v(直接到达)}
}
D[v0] = 0;       // 源点到自身的距离为0
final[v0] = true; // 源点加入“已确定集合”
(2)主循环:逐步确定最短路径

循环G.vexnum - 1次(需确定除源点外所有顶点的最短路径):

for (i = 1; i < G.vexnum; i++) {// 步骤1:找到“未加入集合且距离源点最近”的顶点vmin = MaxInt;for (w = 0; w < G.vexnum; w++) {if (!final[w] && D[w] < min) {  // 未加入集合且距离更小v = w;min = D[w];}}final[v] = true;  // 将v加入“已确定集合”// 步骤2:更新其他未加入集合的顶点到源点的距离for (w = 0; w < G.vexnum; w++) {// 若w未加入集合,且“源点→v→w”的距离 < 当前“源点→w”的距离if (!final[w] && min < MaxInt && G.arcs[v][w] < MaxInt && (min + G.arcs[v][w] < D[w])) {D[w] = min + G.arcs[v][w];  // 更新最短距离// 更新路径:源点到w的路径 = 源点到v的路径 + wfor (j = 0; j < G.vexnum; j++) {p[w][j] = p[v][j];      // 复制源点到v的路径if (p[w][j] == -1) {    // 在路径末尾添加wp[w][j] = w;break;}}}}
}
(3)输出 “距离源点最远的顶点” 及其距离
int k, max = D[0];
for (i = 0; i < G.vexnum; i++) {if (max < D[i]) {  // 找到D数组中的最大值max = D[i];k = i;         // 记录对应顶点(0-based)}
}
cout << k + 1 << endl;  // 转换为1-based输出顶点编号
cout << max << endl;    // 输出最大距离

5.主函数(main函数)

功能:循环读取输入,构建图并调用 Dijkstra 算法,直到输入n=0m=0时退出。

流程:

  1. 读取顶点数n和边数m,若均为 0 则退出;
  2. 调用CreateGraph构建图;
  3. 读取源点v0(1-based),转换为 0-based 后调用ShortestPath_DIJ求解。

6.关键特性与注意事项

  1. 无向图:代码中边是双向的(arcs[s-1][e-1]arcs[e-1][s-1]均赋值);
  2. 非负权重:Dijkstra 算法要求边的权重非负,代码中未做检查,但默认输入满足;
  3. 可达性假设:题目中说明 “该顶点可到达其余各个顶点”,因此无需处理不可达的情况(D[v]不会为MaxInt);
  4. 路径记录p数组详细记录了每条最短路径的顶点序列,可用于后续打印路径。

7.C++代码完整实现

#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MVNum 100     //最大顶点数
#define MaxInt 10000
using namespace std;
typedef char VerTexType;   //设置顶点类型为字符型 
typedef int ArcType;    //设置权重为整型 
typedef struct
{ArcType arcs[MVNum][MVNum];   //邻接矩阵 int vexnum, arcnum;  //顶点数和边数 
}MGraph;
void CreateGraph(MGraph* G,int n,int m);
void ShortestPath_DIJ(MGraph G, int v0, int p[][MVNum], int D[]);//3.途中距离顶点的最短路径长度最大的一个顶点,设该顶点可到达其余各个顶点
int main()
{while(1){MGraph G;int n,m;cin>>n>>m;if(n==0&&m==0){break;}CreateGraph(&G,n,m);int v0,p[MVNum][MVNum],D[MVNum];cin>>v0;ShortestPath_DIJ(G,v0-1,p,D);}
}
void CreateGraph(MGraph* G,int n,int m)
{int i, j;//图的顶点和边数 int s, e, w;//边的起始点,终点,权值 G->vexnum=n;G->arcnum=m;//邻接矩阵初始化for (i = 0; i < G->vexnum; i++){for (j = 0; j < G->vexnum; j++){if(i!=j){G->arcs[i][j] = MaxInt;}else{G->arcs[i][j]=0;}}}for (j = 0; j < G->arcnum; j++){cin >> s >> e >> w;//输入边的起始点,终点,权值G->arcs[s - 1][e - 1] = w;G->arcs[e - 1][s - 1] = w;//矩阵沿对角线对称 }
}
//迪杰斯特拉算法求有向网G的v0顶点到其余顶点v的最短路径p[v]及带权长度D[v]
//p[][]=-1表示没有路径,p[v][i]存的是从v0到v当前求得的最短路径经过的第i+1个顶点(这是打印最短路径的关键),则v0到v的最短路径即为p[v][0]到p[v][j]直到p[v][j]=-1,路径打印完毕。
//final[v]为true当且仅当v∈S,即已经求得从v0到v的最短路径。
void ShortestPath_DIJ(MGraph G, int v0, int p[][MVNum], int D[]) 
{int v, w, i, j, min;bool final[10];for (v = 0; v < G.vexnum; v++) {final[v] = false;//设初值D[v] = G.arcs[v0][v];//D[]存放v0到v得最短距离,初值为v0到v的直接距离for (w = 0; w < G.vexnum; w++){p[v][w] = -1;//设p[][]初值为-1,即没有路径}if (D[v] < MaxInt){ //v0到v有直接路径p[v][0] = v0;//v0到v最短路径经过的第一个顶点p[v][1] = v;//v0到v最短路径经过的第二个顶点}}D[v0] = 0;//v0到v0距离为0final[v0] = true;//v0顶点并入S集for (i = 1; i < G.vexnum; i++) { //其余G.vexnum-1个顶点//开始主循环,每次求得v0到某个顶点v的最短路径,并将v并入S集,然后更新p和Dmin = MaxInt;for (w = 0; w < G.vexnum; w++)//对所有顶点检查{if (!final[w] && D[w] < min){ //在S集之外(即final[]=false)的顶点中找离v0最近的顶点,将其赋给v,距离赋给minv = w;min = D[w];}}final[v] = true;//v并入S集for (w = 0; w < G.vexnum; w++) { //根据新并入的顶点,更新不在S集的顶点到v0的距离和路径数组if (!final[w] && min < MaxInt && G.arcs[v][w] < MaxInt && (min + G.arcs[v][w] < D[w])){//w不属于S集且v0->v->w的距离<目前v0->w的距离D[w] = min + G.arcs[v][w];//更新D[w]for (j = 0; j < G.vexnum; j++) { //修改p[w],v0到w经过的顶点包括v0到v经过的所有顶点再加上顶点wp[w][j] = p[v][j];if (p[w][j] == -1) { //在p[w][]第一个等于-1的地方加上顶点wp[w][j] = w;break;}}}}}int k,max=D[0];for(i=0;i<G.vexnum;i++){if(max<D[i]){max=D[i];k=i;}}cout<<k+1<<endl;cout<<max<<endl;
}

8.Python代码完整实现

import sys# 定义常量,与原C++保持一致
MaxInt = 10000
MVNum = 100  # 最大顶点数,与原C++一致def create_graph(n: int, m: int) -> dict:"""构建无向图的邻接矩阵(对应原C++ CreateGraph函数):param n: 顶点数(1开始编号):param m: 边数:return: 图结构字典,包含顶点数(vexnum)和邻接矩阵(arcs)"""# 初始化邻接矩阵:对角线为0,其余为MaxIntarcs = [[MaxInt for _ in range(n)] for _ in range(n)]for i in range(n):arcs[i][i] = 0  # 自身到自身距离为0# 读取m条边,无向图双向赋值权重for _ in range(m):s, e, w = map(int, sys.stdin.readline().split())# 转换为0开始的索引s_idx = s - 1e_idx = e - 1arcs[s_idx][e_idx] = warcs[e_idx][s_idx] = wreturn {"vexnum": n,"arcs": arcs}def shortest_path_dij(G: dict, v0: int) -> tuple:"""迪杰斯特拉算法(对应原C++ ShortestPath_DIJ函数):param G: 图结构字典:param v0: 起点(0开始编号):return: (最远顶点编号(1开始), 最远距离)"""n = G["vexnum"]# 初始化辅助数组final = [False] * n  # 标记是否已确定最短路径D = [0] * n          # 存储v0到各顶点的最短距离# 路径数组p:p[v][i]表示v0到v的路径第i个顶点(-1表示无后续)p = [[-1 for _ in range(n)] for _ in range(n)]# 初始化D和p数组for v in range(n):D[v] = G["arcs"][v0][v]# 若v0到v有直接路径,初始化路径if D[v] < MaxInt:p[v][0] = v0p[v][1] = v# 起点自身处理D[v0] = 0final[v0] = True# 迭代求其余n-1个顶点的最短路径for i in range(1, n):# 步骤1:找当前未确定最短路径中距离v0最近的顶点vmin_dist = MaxIntv = -1for w in range(n):if not final[w] and D[w] < min_dist:min_dist = D[w]v = wif v == -1:break  # 剩余顶点不可达,提前退出final[v] = True  # 将v加入已确定集合# 步骤2:更新所有未确定顶点的最短距离和路径for w in range(n):if not final[w] and min_dist < MaxInt and G["arcs"][v][w] < MaxInt:if min_dist + G["arcs"][v][w] < D[w]:D[w] = min_dist + G["arcs"][v][w]# 复制v的路径到w,并在末尾添加wj = 0while p[v][j] != -1:p[w][j] = p[v][j]j += 1p[w][j] = w# 找距离v0最远的顶点(可到达的,D[w] < MaxInt)max_dist = -1far_vex = v0  # 默认起点自身for v in range(n):if D[v] < MaxInt and D[v] > max_dist:max_dist = D[v]far_vex = v# 转换为1开始的顶点编号return far_vex + 1, max_distdef main():while True:# 读取顶点数n和边数mline = sys.stdin.readline()while line.strip() == "":  # 跳过空行line = sys.stdin.readline()n, m = map(int, line.strip().split())if n == 0 and m == 0:break  # 输入结束# 构建图G = create_graph(n, m)# 读取起点v0(1开始)v0_line = sys.stdin.readline()while v0_line.strip() == "":v0_line = sys.stdin.readline()v0 = int(v0_line.strip()) - 1  # 转换为0开始# 计算并输出结果far_vex, max_dist = shortest_path_dij(G, v0)print(far_vex)print(max_dist)if __name__ == "__main__":main()

9.Java代码完整实现

import java.util.Scanner;// 常量定义(与原C++一致)
class Constant {public static final int OK = 1;public static final int ERROR = 0;public static final int OVERFLOW = -2;public static final int MVNum = 100; // 最大顶点数public static final int MaxInt = 10000; // 表示无穷大
}// 图结构类(对应原C++的MGraph结构体)
class MGraph {int[][] arcs; // 邻接矩阵int vexnum;   // 顶点数int arcnum;   // 边数// 构造方法(对应原C++的CreateGraph函数)public MGraph(int n, int m, Scanner scanner) {this.vexnum = n;this.arcnum = m;// 初始化邻接矩阵:自身距离为0,其余为无穷大arcs = new int[Constant.MVNum][Constant.MVNum];for (int i = 0; i < this.vexnum; i++) {for (int j = 0; j < this.vexnum; j++) {arcs[i][j] = (i == j) ? 0 : Constant.MaxInt;}}// 读取边信息(无向图:双向赋值权重)for (int j = 0; j < this.arcnum; j++) {int s = scanner.nextInt() - 1; // 转换为0开始索引int e = scanner.nextInt() - 1;int w = scanner.nextInt();arcs[s][e] = w;arcs[e][s] = w;}}
}public class DijkstraAlgorithm {// 迪杰斯特拉算法(对应原C++的ShortestPath_DIJ函数)public static void shortestPathDIJ(MGraph G, int v0) {int n = G.vexnum;boolean[] finalArr = new boolean[n]; // 标记是否已确定最短路径(替换原C++的final数组)int[] D = new int[n];                // 存储v0到各顶点的最短距离int[][] p = new int[Constant.MVNum][Constant.MVNum]; // 存储最短路径// 1. 初始化D、p数组for (int v = 0; v < n; v++) {finalArr[v] = false;D[v] = G.arcs[v0][v];// 初始化路径数组为-1(表示无路径)for (int w = 0; w < Constant.MVNum; w++) {p[v][w] = -1;}// 若v0到v有直接路径,初始化路径if (D[v] < Constant.MaxInt) {p[v][0] = v0;p[v][1] = v;}}// 起点自身处理D[v0] = 0;finalArr[v0] = true;// 2. 迭代求其余n-1个顶点的最短路径for (int i = 1; i < n; i++) {// 找当前未确定路径中距离v0最近的顶点int min = Constant.MaxInt;int v = -1;for (int w = 0; w < n; w++) {if (!finalArr[w] && D[w] < min) {min = D[w];v = w;}}if (v == -1) break; // 剩余顶点不可达,提前退出finalArr[v] = true; // 将v加入已确定集合// 3. 更新所有未确定顶点的距离和路径for (int w = 0; w < n; w++) {if (!finalArr[w] && min < Constant.MaxInt && G.arcs[v][w] < Constant.MaxInt && (min + G.arcs[v][w] < D[w])) {// 更新最短距离D[w] = min + G.arcs[v][w];// 复制v的路径到w,并追加w作为终点int j = 0;while (p[v][j] != -1) {p[w][j] = p[v][j];j++;}p[w][j] = w;}}}// 4. 找距离v0最远的顶点(与原C++逻辑一致)int maxDist = D[0];int farVex = 0;for (int i = 0; i < n; i++) {if (D[i] > maxDist) {maxDist = D[i];farVex = i;}}// 输出结果(转换为1开始的顶点编号)System.out.println(farVex + 1);System.out.println(maxDist);}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);while (true) {// 读取顶点数n和边数mint n = scanner.nextInt();int m = scanner.nextInt();if (n == 0 && m == 0) {break; // 输入结束,退出循环}// 构建图(读取m条边)MGraph G = new MGraph(n, m, scanner);// 读取起点v0(转换为0开始索引)int v0 = scanner.nextInt() - 1;// 执行迪杰斯特拉算法并输出结果shortestPathDIJ(G, v0);}scanner.close();}
}

10.总结

本文实现了一个基于Dijkstra算法的图最短路径求解系统,用于找到图中距离指定顶点最远顶点及其最短距离。系统核心功能包括:

(1)构建无向图邻接矩阵;

(2)使用Dijkstra算法计算单源最短路径;

(3)找出距离源点最远的顶点。

实现采用邻接矩阵存储图结构,包含C++、Python和Java三种语言版本,支持多组数据输入。算法时间复杂度为O(n²),适用于顶点数不超过100的图。测试样例验证了系统在无向图、带权边等场景下的正确性,满足题目要求的输入输出格式和功能需求。

http://www.dtcms.com/a/507079.html

相关文章:

  • 网站后台管理产品排序网站被黑是怎么回事
  • jinji2模板
  • Linux route
  • 接10月12日---队列笔记
  • 第四章 串、数组和广义表——课后习题解练【数据结构(c语言版 第2版)】
  • 从C语言标准揭秘C指针:第 10 章:指针与动态内存:堆区内存的生命周期管理
  • 设计汽车网站外贸建站服务器怎么选
  • 微网站制作超链接太原网站开发工程师
  • 服装生产管理系统|基于SpringBoot和Vue的服装生产管理系统(源码+数据库+文档)
  • 牛客101:链表
  • 量化策略中三周期共振策略的仓位管理方法
  • 【python】快速实现pdf批量去除指定位置水印
  • 在 macOS 上用 Docker 为 Java 后端 常见开发需求搭建完整服务(详尽教程)
  • 网站建设翻译网站添加二维码
  • Debug —— Docker配置镜像后下载Mysql等报连接超时
  • 中冶交通建设集团网站发网站视频做啥格式最好
  • 软件定制一条龙整站多关键词优化
  • 【Vscode】显示多个文件 打开多个文件时实现标签栏多行显示
  • vue 技巧与易错
  • vscode编写Markdown文档
  • 使用VScode 插件,连接MySQL,可视化操作数据库
  • 基于微信小程序的公益捐赠安全平台9hp4t247 包含完整开发套件(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
  • 【论文精读】FlowVid:驯服不完美的光流,实现一致的视频到视频合成
  • 【C++】滑动窗口算法习题
  • C语言趣味小游戏----扫雷游戏
  • 三款AI平台部署实战体验:Dify、扣子与BuildingAI深度对比
  • 网站制作难不难小红书搜索优化
  • Python如何使用NumPy对图像进行处理
  • 房产中介网站开发站长工具之家
  • Linux服务器编程实践60-双向管道:socketpair函数的实现与应用场景