数学建模之图论

news2024/11/17 6:45:54

目录

  • 1 图的基本概念
  • 2 如何做图
    • 2.1 直接做图
    • 2.2 编程做图
  • 3 权重邻接矩阵
    • 3.1 无向图
    • 3.2 有向图
  • 4 Dijkstra 算法
    • 4.1 算法概述
    • 4.2 代码实现
  • 5 Floyd 算法
    • 5.1 算法概述
    • 5.2 代码实现
  • 6 思考题

1 图的基本概念


图论中的图(Graph)是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。

一个图可以用数学语言描述为:G(V(G),E(G))V(vertex)指的是图的顶点集,E(edge)指的是图的边集。

根据边是否有方向,可将图分为无向图有向图。另外,有些图的边上还可能有权值,这样的图称为有权图

在这里插入图片描述

2 如何做图

2.1 直接做图


在线做图工具的网址

在这里插入图片描述

2.2 编程做图


无向图

  • graph(s,t):可在 st中的对应节点之间创建边,并生成一个图
  • graph(s,t,w):可在 st 中的对应节点之间以 w 的权重创建边,并生成一个图

要做出有向图,只需要将 graph 改为 digraph 就行了。

1️⃣ 无向图

% 无权重,也可以说每条边的权重默认为1
s1 = [1,2,3,4];
t1 = [2,3,1,1];
% 函数graph(s,t):可在 s 和 t 中的对应节点之间创建边,并生成一个图
% s 和 t 都必须具有相同的元素数;这些节点必须都是从1开始的正整数,或都是字符串元胞数组。
G1 = graph(s1, t1);
plot(G1)

% 注意字符串元胞数组是用大括号包起来的哦
s2 = {'学校','电影院','网吧','酒店'};
t2 = {'电影院','酒店','酒店','KTV'};
G2 = graph(s2, t2);
plot(G2, 'linewidth', 2)  % 设置线的宽度
% 下面的命令是在画图后不显示坐标
set( gca, 'XTick', [], 'YTick', [] );  

% 有权重
s = [1,2,3,4];
t = [2,3,1,1];
w = [3,8,9,2];
% 函数graph(s,t,w):可在 s 和 t 中的对应节点之间以w的权重创建边,并生成一个图
G = graph(s, t, w);
plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2) 
set( gca, 'XTick', [], 'YTick', [] );  

在这里插入图片描述
在这里插入图片描述

❗️注意:

  • 注意哦,编号只能从1开始连续编号(否则会报错),不要自己随便定义编号,因为默认连续编号,不写也有
s = [1,2,3,50];
t = [2,3,1,1];
G = graph(s, t);
plot(G)

在这里插入图片描述

2️⃣ 有向图

% 无权图 digraph(s,t)
s = [1,2,3,4,1];
t = [2,3,1,1,4];
G1 = digraph(s, t);
plot(G1)
set( gca, 'XTick', [], 'YTick', [] );  

% 有权图 digraph(s,t,w)
s = [1,2,3,4];
t = [2,3,1,1];
w = [3,8,9,2];
G2 = digraph(s, t, w);
plot(G2, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2) 
set( gca, 'XTick', [], 'YTick', [] );  

在这里插入图片描述

☀️ 总结:

  • Matlab做出来的图不是很漂亮,要是节点比较少,还是推荐使用在线

3 权重邻接矩阵


3.1 无向图


在这里插入图片描述

3.2 有向图


在这里插入图片描述

4 Dijkstra 算法

4.1 算法概述


图中有 0~8 共九个地点,地点之间若用直线连接,则表明两地可直接到达,直线旁的数值表示两地的距离。

问起点为0,终点为4,怎么走路程最短?


在这里插入图片描述

使用 Dijkstra 算法解决上述问题

1️⃣ 初始化

Visited:所有的节点都是未访问的状态;
Distance:所有节点间的距离都是 Inf
Parent:所有节点的父节点(上一个节点)都是 -1,表示不存在

在这里插入图片描述

1️⃣ 起点是0,更新表格:

  • 节点0的访问状态变为1
  • 节点0对应的距离变为0
  • 节点0的父节点用0表示,当然用其他符号表示都可以

在这里插入图片描述

2️⃣ 更新与节点0(A)相邻节点(B)的信息,注意,这里的B节点是未访问的

  • 如果A与B的距离 + A的距离小于B的距离,那么我们就将B的距离更新为较小的距离,并将B的父节点更新为A,并建行较小距离的节点纳入访问过的节点中

在这里插入图片描述

在这里插入图片描述

3️⃣ 更新与节点1(A)相邻节点(B)的信息,注意,这里的B节点是未访问的

  • 如果A与B的距离 + A的距离小于B的距离,那么我们就将B的距离更新为较小的距离,并将B的父节点更新为A,并建行较小距离的节点纳入访问过的节点中

在这里插入图片描述

在这里插入图片描述

4️⃣ 重复上述步骤,最终得到:

在这里插入图片描述

根据以上结果,我们可以得到节点0到节点4的最短路径:

在这里插入图片描述

Dijkstra 算法一般用于无向图求最短路径,也可以用于有向图,但是Dijkstra 算法的一个缺点即不能用于处理有负权重的图

在这里插入图片描述


Bellman‐Ford 算法


为了解决Dijkstra 算法不能用于处理有负权重图的缺点,提出了 Bellman‐Ford 算法

事实上,Bellman‐Ford 算法不再将节点区分为是否已访问的状态,因为Bellman‐Ford 算法是利用循环来进行更新权重的,且每循环一次,Bellman‐Ford 算法都会更新所有的节点的信息。

Bellman‐Ford 算法不支持含有负权回路的图(Floyd算法也不可以)

在这里插入图片描述

4.2 代码实现


[P,d] = shortestpath(G,start,end [,'Method',algorithm])

  • 功能:返回图 Gstart 节点到 end 节点的最短路径

  • 输入参数:

    • G: 输入图(graph 对象 或 digraph 对象)
    • start :起始的节点
    • end :目标的节点
    • [,‘Method’,algorithm]:是可选的参数,表示计算最短路径的算法。一般我们不用手动设置,默认使用的是 auto
      在这里插入图片描述
  • 输出参数:

    • P 最短路径经过的节点
    • d 最短距离

示例代码:

%% 注意:以下代码需要较新版本的matlab才能运行(最好是2016版本及以上)
% 如果运行出错请下载新版的matlab代码再运行

% 注意哦,Matlab中的图节点要从1开始编号,所以这里把0全部改为了9
% 编号最好是从1开始连续编号,不要自己随便定义编号
s = [9 9 1 1 2 2 2 7 7 6 6  5  5 4];
t = [1 7 7 2 8 3 5 8 6 8 5  3  4 3];
w = [4 8 3 8 2 7 4 1 6 6 2 14 10 9];
G = graph(s,t,w);
plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2) 
set( gca, 'XTick', [], 'YTick', [] );  
[P,d] = shortestpath(G, 9, 4)  %注意:该函数matlab2015b之后才有哦

% 在图中高亮我们的最短路径
myplot = plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2);  %首先将图赋给一个变量
highlight(myplot, P, 'EdgeColor', 'r')   %对这个变量即我们刚刚绘制的图形进行高亮处理(给边加上r红色)

% 求出任意两点的最短路径矩阵
D = distances(G)   %注意:该函数matlab2015b之后才有
D(1,2)  % 1 -> 2的最短路径
D(9,4)  % 9 -> 4的最短路径

% 找出给定范围内的所有点  nearest(G,s,d)
% 返回图形 G 中与节点 s 的距离在 d 之内的所有节点
[nodeIDs,dist] = nearest(G, 2, 10)   %注意:该函数matlab2016a之后才有

输出图形:

在这里插入图片描述

5 Floyd 算法

5.1 算法概述


Floyd 算法是解决任意两点间的最短路径的一种算法,可以正确处理无向图或有向图(可以有负权重,但不可存在负权回路)的最短路径问题。

Floyd 算法与 Dijkstra 算法或Bellman‐Ford 算法相比,能够一次性的求出任意两点之间的最短路径,后两种算法运行一次只能计算出给定的起点和终点之间的最短路径。当然,Floyd 算法计算的时间也要高于后两种算法,其算法核心的步骤由三层循环构成。

算法动画展示

在这里插入图片描述
从上面观察到的两个结论中,我们不难提炼出下面这个思想:

  • 假设现在有一个起点A和终点B,那么对于其他任意的中间点M:
    D(A,B) ≤ D(A,M) + D(M,B) ,这里,D(X,Y)表示X和Y两点之间的最短距离。

因此,Floyd算法实际上核心在于一个三层循环

5.2 代码实现


☀️ 实现计算任意两点之间的最短路径的距离


在这里插入图片描述


☀️ 求最短路径(记录最短路径经过的点)


在这里插入图片描述

在这里插入图片描述

将伪代码转换为 Matlab 代码

在这里插入图片描述


1️⃣ 定义Floyd 算法的函数Floyd_algorithm.m

function [dist,path] = Floyd_algorithm(D)
%% 该函数用于求解一个权重邻接矩阵任意两个节点之间的最短路径
% 输入:
%        D是权重邻接矩阵
% 输出:
%        dist是最短距离矩阵,其元素dist_ij表示表示i,j两个节点的最短距离
%        path是路径矩阵,其元素path_ij表示起点为i,终点为j的两个节点之间的最短路径要经过的节点

n = size(D,1);  % 计算节点的个数

% 初始化dist矩阵
dist = D;

% 下面我们来初始化path矩阵
path = zeros(n);
for j = 1:n
    path(:,j) = j;   % 将第j列的元素变为j
end
for i = 1:n
    path(i,i) = -1;  % 将主对角线元素变为-1
end

% 下面开始三个循环
for k=1:n    % 中间节点k从1- n 循环
   for i=1:n     % 起始节点i从1- n 循环
      for j=1:n    % 终点节点j从1-n 循环
          if dist(i,j)>dist(i,k)+dist(k,j)  % 如果i,j两个节点间的最短距离大于i和k的最短距离+k和j的最短距离
             dist(i,j)=dist(i,k)+dist(k,j);  % 那么我们就令这两个较短的距离之和取代i,j两点之间的最短距离
             path(i,j)=path(i,k);   % 起点为i,终点为j的两个节点之间的最短路径要经过的节点更新为path(i,k)
             % 注意,上面一行语句不能写成path(i,j) = k
          end
      end
   end
end

end

2️⃣ 定义打印任意两节点间的最短路径的函数 print_path.m

function [] = print_path(path,dist,i,j)
%% 该函数的作用是打印从i到j经过的最短路径
% 输入:
%        path是使用floyd算法求出来的路径矩阵
%        dist是使用floyd算法求出来的最短距离矩阵
%        i是起始节点的编号
%        j是终点节点的编号
% 输出:无

if i == j
    warning('起点和终点相同,请检查后重新输入')  % 在屏幕中提示警告信息
    return;  % 不运行下面的语句,直接退出函数
end
if path(i,j) == j   % 如果path(i,j) = j,则有两种可能:
% (1)如果dist(i,j) 为 Inf , 则说明从i到j没有路径可以到达
    if dist(i,j) == Inf
        disp(['从',num2str(i),'到',num2str(j),'没有路径可以到达'])
% (2)如果dist(i,j) 不为 Inf , 则说明从i到j可直接到达,且为最短路径
    else
        disp(['从',num2str(i),'到',num2str(j),'的最短路径为'])
        disp([num2str(i),' ---> ',num2str(j)])
        disp(['最短距离为',num2str(dist(i,j))])
    end
else  % 如果path(i,j) ~= j,则说明中间经过了其他节点:
    k = path(i,j);
    result = [num2str(i),' ---> '];  % 初始化要打印的这个字符串
    while k ~= j  % 只要k不等于j, 就一直循环下去
        result = [result , num2str(k) , ' ---> ' ];  % i先走到k这个节点处
        k = path(k,j);
    end
    result = [result , num2str(k)];
    disp(['从',num2str(i),'到',num2str(j),'的最短路径为'])
    disp(result)
    disp(['最短距离为',num2str(dist(i,j))])
end

end

在这里插入图片描述


3️⃣ 定义打印所有的任意两节点间的最短路径的函数 print_all_path.m

function [] = print_all_path(D)
%% 该函数的作用是求解一个权重邻接矩阵任意两个节点之间的最短路径,并打印所有的结果出来
% 输入:
%        D是权重邻接矩阵
% 输出:无

[dist,path] = Floyd_algorithm(D);   % 调用之前的Floyd_algorithm函数
n = size(D,1);
if n == 1
    warning('请输入至少两阶以上的权重邻接矩阵')   % 在屏幕中提示警告信息
    return;   % 不运行下面的语句,直接退出函数
end

for i = 1:n
    for j = 1:n
        if i ~= j  % 不等号用~=表示
            print_path(path,dist,i,j);   % 调用之前的print_path函数
            disp('-------------------------------------------')
            disp('  ')
        end
    end
end

end

在这里插入图片描述


4️⃣ 将图转换为权重邻接矩阵D,并调用 Floyd 算法的函数

%% 首先将图转换为权重邻接矩阵D
n = 5;  %一共五个节点
D = ones(n) ./ zeros(n);  % 全部元素初始化为Inf【有向图】
for i = 1:n
    D(i,i) = 0;  % 主对角线元素为0
end
D(1,2) = 3;
D(1,3) = 8;
D(1,5) = -4;
D(2,5) = 7;
D(2,4) = 1;
D(3,2) = 4;
D(4,3) = -5;
D(5,4) = 6;
D(4,1) = 2;

%% 调用Floyd_algorithm函数求解
[dist,path] = Floyd_algorithm(D)

print_path(path,dist,1,5)
print_path(path,dist,1,4)
print_path(path,dist,3,1)

clc
disp('下面我们打印任意两点之间的最短距离:')
print_all_path(D)

6 思考题


求出任意两点间的最短路径

在这里插入图片描述

参考答案:

%% 首先将图转换为权重邻接矩阵D
n = 9; %一共9个节点
D = zeros(n); % 全部元素初始化为0 【无向图】
% 因为是无向图,所以权重邻接矩阵是一个对称矩阵
D(1,2) = 4; D(1,8) = 8;
D(2,8) = 3; D(2,3) = 8;
D(8,9) = 1; D(8,7) = 6;
D(9,7) = 6; D(9,3) = 2;
D(7,6) = 2; D(3,4) = 7;
D(3,6) = 4; D(6,4) = 14;
D(4,5) = 9; D(6,5) = 10;
D = D+D'; % 这个操作可以得到对称矩阵的另一半
for i = 1:n
for j = 1:n
if (i ~= j) && (D(i,j) == 0) 
D(i,j) = Inf; % 将非主对角线上的0元素全部变为Inf
end
end
end
%% 调用Floyd_algorithm函数求解
[dist,path] = Floyd_algorithm(D)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/972631.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mkp勒索病毒的介绍和防范,勒索病毒解密,数据恢复

mkp勒索病毒是一种新兴的电脑病毒,它会对感染的电脑进行加密,并要求用户支付一定的赎金才能解锁。这种病毒已经引起了全球范围内的关注,因为它不仅具有高危害性,而且还有很强的传播能力。本文将对mkp勒索病毒进行详细介绍&#xf…

群辉NAS:J1900系统盘安装SATA固态硬盘方案【自留记录】

群辉NAS:J1900系统盘安装SATA固态硬盘方案 设备介绍: DSM版本:918 主板CPU:蜗牛星际J1900板 内存:8G DDR3 固态:移速SATA固态(msata在win微桌面识别,群晖安装时候识别不到&#xf…

pdf用什么软件打开?介绍几种常用打开方法

pdf用什么软件打开?PDF是一种广泛使用的文件格式,由于其跨平台和易于共享的特点,它已成为许多人在日常工作和学习中使用的首选文件格式。但是,有时候我们可能会遇到一些问题,比如不知道用什么软件打开PDF文件&#xff…

Hadoop生态之hive

一 概述与特点 之所以把Hive放在Hadoop生态里面去写,是因为它本身依赖Hadoop。Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类 SQL 查询功能。 其本质是将 SQL 转换为 MapReduce/Spark 的任务进行运算,底层由 HDFS 来提供…

软件测试/测试开发丨Web自动化 PageObject设计模式

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接:https://ceshiren.com/t/topic/27167 一、page object 模式简介 马丁福勒个人博客 selenium 官网 1.1、传统 UI 自动化的问题 无法适应 UI 频繁变化无法清晰表达业务用例场景大量的样…

微任务创建 -- queueMicrotask()

微任务创建方式: Promise.then(()>{})Mutation Observer()queueMicrotask() 本文主要介绍queueMicrotask()的使用。 queueMicrotask的使用 Window 或 Worker 接口的 queueMicrotask() 方法,将微任务加入队列以在控制返回浏览器的事件循环之前的安全…

Git 版本回退 超神步骤

Git 版本回退 一. 背景 多版本分支开发,合并版本问题太多,需要回滚到某次版本。我的git客服端工具是 sourcetree 二.操作步骤 2.1 切到当前需要回退版本的分支 2.2 右击需要具体某一个分支,这个分支就是你想切到的分支版本,具体…

正版软件 | CloudDrive 多云盘本地挂载管理工具

前言: CloudDrive 是一个强大的多云盘管理工具,提供一站式的多云盘解决方案,包括云盘本地挂载。旨在无缝集成多个云存储服务,统一整合到一个界面。轻松管理和访问所有云存储服务,无需在不同的应用程序和界面之间切换。…

虚拟现实vr元宇宙井下危险隐患排查模拟实训稳固企业生产

数字化时代,职业教育正面临着前所未有的挑战和机遇,元宇宙的兴起,借助元宇宙平台进行钻井虚拟教学实验,基于元宇宙数字空间搭建更丰富、逼真、安全、灵活的实验环境,成为石油行业教育创新的催化剂。 一、降低实验成本 …

Excel·VBA二维数组组合函数的应用实例

看到一个问题《关于#穷举#的问题,如何解决?(语言-开发语言)》,对同一个数据存在“是/否”2种状态,判断其是否参与计算,并输出一系列数据的“是/否”状态的结果 目录 方法1:二维数组组合函数结果 方法2&am…

树上钟同步

#include<cstdio> #include<cstring> #include<vector> using namespace std;const int N 2505; int ori[N], f[N]; vector<int> edge[N]; // 邻接表的简单实现形式void dfs(int u, int fa) {for (int v : edge[u]) {if (v fa) continue;dfs(v, u);f…

网络协议从入门到底层原理学习(一)—— 简介及基本概念

文章目录 网络协议从入门到底层原理学习&#xff08;一&#xff09;—— 简介及基本概念一、简介1、网络协议的定义2、网络协议组成要素3、广泛的网络协议类型网络通信协议网络安全协议网络管理协议 4、网络协议模型对比图 二、基本概念1、网络互连模型2、计算机之间的通信基础…

Prompt Tuning训练过程

目录 0. 入门 0.1. NLP发展的四个阶段&#xff1a; Prompt工程如此强大&#xff0c;我们还需要模型训练吗&#xff1f; - 知乎 Prompt learning系列之prompt engineering(二) 离散型prompt自动构建 Prompt learning系列之训练策略篇 - 知乎 ptuning v2 的 chatglm垂直领域训练记…

【zookeeper】zookeeper日常运维

本文将分享一些zookeeper在日常使用中一些维护经验。 zookeeper清理快照 脚本或者命令清理 zookeeper长时间运行&#xff0c;快照逐渐增多可能造成服务器磁盘被占满的情况&#xff0c;但我们不能贸然用rm命令删除快照文件&#xff0c;如果直接删完会导致丢失好多数据&#x…

【Yellowbrick】特征可视化分析

Yellowbrick特征可视化分析 ⭐Yellowbrick⭐特征分析可视化⭐Rank1D⭐Rank2D ⭐Yellowbrick Yellowbrick是一个用于可视化机器学习模型和评估性能的Python库。它提供了一系列高级可视化工具&#xff0c;帮助数据科学家和机器学习从业者更好地理解、调试和优化他们的模型。 它在…

【【STM32-29正点原子版本串口发送传输实验】

STM32-29正点原子版本串口发送传输实验 通过串口接收或发送一个字符 例程目的 开发板上我们接入的是实现异步通信的UART接口 USB转串口原理图 我们一步步分析 PA9是串口1 的发送引脚 PA10是串口1 的接受引脚 。因为我们现在只是用到异步收发器功能&#xff0c;所以我们现…

应用可视化流程设计,实现提质增效流程化办公!

如果想要实现提高办公效率的目的&#xff0c;显然采用传统的办公方式是无法实现的。如今&#xff0c;在低代码技术平台深入无纸化办公的当下&#xff0c;应用可视化流程设计软件&#xff0c;可以借助其灵活、易操作、可视化、轻量级等优势特点&#xff0c;助力广大用户实现流程…

图解SQL查询之去重技巧:如何使用DISTINCT对数据进行去重

使用 SQL 的 DISTINCT 关键字&#xff0c;可以去除重复的数据记录&#xff0c;只保留不同的记录。 以下是用到的表。 例如&#xff0c;要获取所有学生所在班级的唯一班级ID。

工业4G路由器的户外组网与无人值守场景应用

工业4G路由器是专为不便电缆布线的工业或日晒雨淋网络不畅的户外环境所设计的网络设备。它能够在没有光纤宽带的情况下使用插卡的方式提供4G或无线WiFi的网络支持。具备工业级防水功能&#xff0c;能够在户外环境下进行网络部署&#xff0c;并实现无人值守运行。工业4G路由器还…

使用Xshell串口通过Ymodem协议发送文件

一. 虚拟串口 首先使用虚拟串口软件Free Virtual Serial Ports&#xff08;下载链接&#xff09;创建一对虚拟串口&#xff0c;如图COM1和COM2&#xff0c;然后COM1用Xshell连接&#xff0c;COM2用串口助手连接&#xff0c;二者连接的波特率需一致&#xff1b;Xshell创建串口连…