赞
踩
专栏:数学建模学习笔记
- % MATLAB代码
- % 创建无向图和有向图的邻接矩阵表示
-
- % 无向图的邻接矩阵
- A_undirected = [0 1 1 0;
- 1 0 1 1;
- 1 1 0 1;
- 0 1 1 0];
-
- % 有向图的邻接矩阵
- A_directed = [0 1 0 0;
- 0 0 1 0;
- 0 0 0 1;
- 1 0 0 0];
-
- % 显示邻接矩阵
- disp('无向图的邻接矩阵:');
- disp(A_undirected);
-
- disp('有向图的邻接矩阵:');
- disp(A_directed);
-
- % 创建图对象并可视化
- G_undirected = graph(A_undirected);
- G_directed = digraph(A_directed);
-
- % 绘制图
- figure;
- subplot(1,2,1);
- plot(G_undirected);
- title('无向图');
-
- subplot(1,2,2);
- plot(G_directed);
- title('有向图');
- 无向图的邻接矩阵:
- 0 1 1 0
- 1 0 1 1
- 1 1 0 1
- 0 1 1 0
-
- 有向图的邻接矩阵:
- 0 1 0 0
- 0 0 1 0
- 0 0 0 1
- 1 0 0 0
- 邻接矩阵表示
-
- 无向图的邻接矩阵:A_undirected 是一个4x4矩阵,其中 A_undirected(i, j) 表示顶点 i 和顶点 j 之间是否有边。对于无向图,矩阵是对称的。
- 有向图的邻接矩阵:A_directed 是一个4x4矩阵,其中 A_directed(i, j) 表示顶点 i 到顶点 j 之间是否有边。对于有向图,矩阵不是对称的。
- 显示邻接矩阵
-
- 使用 disp 函数显示无向图和有向图的邻接矩阵,以便于检查矩阵的正确性。
- 创建图对象并可视化
-
- graph(A_undirected) 创建无向图对象。
- digraph(A_directed) 创建有向图对象。
- 使用 plot 函数可视化图对象。subplot 函数将图分成两部分,分别显示无向图和有向图。
- import networkx as nx
- import matplotlib.pyplot as plt
- import numpy as np
- from matplotlib.font_manager import FontProperties
-
- # 设置中文字体
- font = FontProperties(fname=r"C:\Windows\Fonts\simsun.ttc", size=15)
-
- # 无向图的邻接矩阵
- A_undirected = np.array([
- [0, 1, 1, 0],
- [1, 0, 1, 1],
- [1, 1, 0, 1],
- [0, 1, 1, 0]
- ])
-
- # 有向图的邻接矩阵
- A_directed = np.array([
- [0, 1, 0, 0],
- [0, 0, 1, 0],
- [0, 0, 0, 1],
- [1, 0, 0, 0]
- ])
-
- # 使用邻接矩阵创建无向图和有向图
- G_undirected = nx.from_numpy_array(A_undirected)
- G_directed = nx.from_numpy_array(A_directed, create_using=nx.DiGraph)
-
- # 绘制无向图
- plt.figure(figsize=(10, 5))
- plt.subplot(1, 2, 1)
- nx.draw(G_undirected, with_labels=True, node_color='skyblue', edge_color='black', node_size=1500, font_size=20)
- plt.title('无向图', fontproperties=font)
-
- # 绘制有向图
- plt.subplot(1, 2, 2)
- nx.draw(G_directed, with_labels=True, node_color='lightgreen', edge_color='red', node_size=1500, font_size=20, arrows=True)
- plt.title('有向图', fontproperties=font)
-
- plt.show()
- 注意的细节知识点
-
- 邻接矩阵表示
-
- 确保邻接矩阵的对称性(对于无向图)。
- 邻接矩阵的大小应为 n x n,其中 n 是顶点数量。
- 显示矩阵
-
- 使用 disp 或 print 函数显示矩阵,便于检查矩阵的正确性。
- 创建图对象
-
- 使用 graph 和 digraph 函数分别创建无向图和有向图对象。
- 确保输入的邻接矩阵符合图的类型(无向或有向)。
- 可视化图
-
- 使用 plot 函数可视化图对象,便于直观理解图的结构。
- 在Python中,可以使用 networkx 库中的 draw 函数进行可视化,matplotlib 库中的 subplot 函数分割图形窗口。
- MATLAB和Python的差异
-
- MATLAB中的 graph 和 digraph 函数对应于Python中的 nx.Graph 和 nx.DiGraph。
- MATLAB中的 disp 函数对应于Python中的 print 函数。
- MATLAB中的 plot 函数对应于Python中的 nx.draw 函数。
- 初始化:设置起点到自己的距离为0,其他顶点为无穷大。
- 选择未处理的顶点中距离最小的顶点,将其标记为已处理。
- 更新该顶点的邻接顶点的距离。
- 重复步骤2和3,直到所有顶点都被处理。
- % MATLAB代码
- % Dijkstra算法实现
- function [dist, path] = dijkstra(A, start_node)
- n = size(A, 1); % 顶点数量
- dist = inf(1, n); % 初始化距离
- dist(start_node) = 0;
- visited = false(1, n); % 访问标记
- path = -ones(1, n); % 路径
-
- for i = 1:n
- % 选择未处理顶点中距离最小的顶点
- [~, u] = min(dist + visited * inf);
- visited(u) = true;
-
- % 更新邻接顶点的距离
- for v = 1:n
- if A(u, v) > 0 && ~visited(v)
- alt = dist(u) + A(u, v);
- if alt < dist(v)
- dist(v) = alt;
- path(v) = u;
- end
- end
- end
- end
- end
-
- % 示例图的邻接矩阵
- A = [0 10 20 0 0;
- 10 0 5 1 0;
- 20 5 0 2 3;
- 0 1 2 0 4;
- 0 0 3 4 0];
-
- % 计算从起点1到其他顶点的最短路径
- [start_node] = 1;
- [dist, path] = dijkstra(A, start_node);
-
- % 显示结果
- disp('顶点的最短距离:');
- disp(dist);
- disp('最短路径:');
- disp(path);
-
- % 可视化结果
- G = digraph(A);
- figure;
- h = plot(G, 'EdgeLabel', G.Edges.Weight);
- highlight(h, path, 'EdgeColor', 'r', 'LineWidth', 2);
- title('Dijkstra最短路径');
- 顶点的最短距离:
- 0 10 20 Inf Inf
-
- 最短路径:
- -1 1 1 -1 -1
- 初始化
-
- n = size(A, 1):获取图中顶点的数量。
- dist = inf(1, n):初始化每个顶点的距离为无穷大。
- dist(start_node) = 0:起点到自身的距离为0。
- visited = false(1, n):初始化访问标记。
- path = -ones(1, n):初始化路径数组。
- 主循环
-
- for i = 1:n:对每个顶点进行迭代。
- [~, u] = min(dist + visited * inf):选择未处理顶点中距离最小的顶点。
- visited(u) = true:将该顶点标记为已处理。
- 更新邻接顶点的距离
-
- for v = 1:n:对每个邻接顶点进行迭代。
- if A(u, v) > 0 && ~visited(v):如果顶点 v 与顶点 u 之间有边且未被访问。
- alt = dist(u) + A(u, v):计算通过顶点 u 到顶点 v 的距离。
- if alt < dist(v):如果通过 u 到 v 的距离小于当前已知的 v 的距离。
- dist(v) = alt:更新 v 的距离。
- path(v) = u:更新 v 的路径。
- import heapq
-
- def dijkstra(A, start_node):
- n = len(A)
- dist = [float('inf')] * n
- dist[start_node] = 0
- visited = [False] * n
- path = [-1] * n
- queue = [(0, start_node)]
-
- while queue:
- d, u = heapq.heappop(queue)
- if visited[u]:
- continue
- visited[u] = True
-
- for v, weight in enumerate(A[u]):
- if weight > 0 and not visited[v]:
- alt = dist[u] + weight
- if alt < dist[v]:
- dist[v] = alt
- path[v] = u
- heapq.heappush(queue, (alt, v))
-
- return dist, path
-
- # 示例图的邻接矩阵
- A = [
- [0, 10, 20, 0, 0],
- [10, 0, 5, 1, 0],
- [20, 5, 0, 2, 3],
- [0, 1, 2, 0, 4],
- [0, 0, 3, 4, 0]
- ]
-
- # 计算从起点0到其他顶点的最短路径
- start_node = 0
- dist, path = dijkstra(A, start_node)
-
- # 显示结果
- print('顶点的最短距离:', dist)
- print('最短路径:', path)
- 顶点的最短距离: [0, 10, 13, 11, 15]
- 最短路径: [-1, 0, 3, 1, 3]
- % MATLAB代码
- % Kruskal算法实现
- function [mst_edges, mst_weight] = kruskal(A)
- n = size(A, 1);
- edges = [];
- for i = 1:n
- for j = i+1:n
- if A(i, j) > 0
- edges = [edges; i, j, A(i, j)];
- end
- end
- end
- edges = sortrows(edges, 3);
-
- parent = 1:n;
- mst_edges = [];
- mst_weight = 0;
-
- function p = find(parent, x)
- if parent(x) == x
- p = x;
- else
- p = find(parent, parent(x));
- parent(x) = p;
- end
- end
-
- for k = 1:size(edges, 1)
- u = edges(k, 1);
- v = edges(k, 2);
- w = edges(k, 3);
- pu = find(parent, u);
- pv = find(parent, v);
- if pu ~= pv
- mst_edges = [mst_edges; u, v];
- mst_weight = mst_weight + w;
- parent(pu) = pv;
- end
- end
- end
-
- % 示例图的邻接矩阵
- A = [0 10 6 5;
- 10 0 0 15;
- 6 0 0 4;
- 5 15 4 0];
-
- % 计算最小生成树
- [mst_edges, mst_weight] = kruskal(A);
-
- % 显示结果
- disp('最小生成树的边:');
- disp(mst_edges);
- disp('最小生成树的权重:');
- disp(mst_weight);
-
- % 可视化结果
- G = graph(A);
- figure;
- h = plot(G, 'EdgeLabel', G.Edges.Weight);
- highlight(h, mst_edges(:,1), mst_edges(:,2), 'EdgeColor', 'r', 'LineWidth', 2);
- title('Kruskal最小生成树');
- 最小生成树的边:
- 3 4
- 1 4
- 1 2
-
- 最小生成树的权重:
- 19
- 初始化
-
- n = size(A, 1):获取图中顶点的数量。
- edges = []:初始化边的列表。
- 使用嵌套循环遍历邻接矩阵,收集所有边的信息。
- 边的排序
-
- edges = sortrows(edges, 3):按边的权值从小到大排序。
- 并查集的初始化
-
- parent = 1:n:初始化每个顶点的父节点为自身。
- mst_edges = []:初始化最小生成树的边列表。
- mst_weight = 0:初始化最小生成树的权重和。
- 并查集查找函数
-
- function p = find(parent, x):递归查找顶点的根节点,并进行路径压缩。
- class UnionFind:
- def __init__(self, n):
- self.parent = list(range(n))
-
- def find(self, u):
- if self.parent[u] != u:
- self.parent[u] = self.find(self.parent[u])
- return self.parent[u]
-
- def union(self, u, v):
- root_u = self.find(u)
- root_v = self.find(v)
- if root_u != root_v:
- self.parent[root_u] = root_v
-
- def kruskal(A):
- n = len(A)
- edges = [(A[i][j], i, j) for i in range(n) for j in range(i + 1, n) if A[i][j] > 0]
- edges.sort()
-
- uf = UnionFind(n)
- mst_edges = []
- mst_weight = 0
-
- for weight, u, v in edges:
- if uf.find(u) != uf.find(v):
- uf.union(u, v)
- mst_edges.append((u, v))
- mst_weight += weight
-
- return mst_edges, mst_weight
-
- # 示例图的邻接矩阵
- A = [
- [0, 10, 6, 5],
- [10, 0, 0, 15],
- [6, 0, 0, 4],
- [5, 15, 4, 0]
- ]
-
- # 计算最小生成树
- mst_edges, mst_weight = kruskal(A)
-
- # 显示结果
- print('最小生成树的边:', mst_edges)
- print('最小生成树的权重:', mst_weight)
初始化
- 确保并查集正确初始化,每个顶点的父节点为自身。
边的收集与排序
- 收集所有边的信息,并按权值从小到大排序,以便于后续选择最小权值边。
并查集查找函数
- 使用递归查找顶点的根节点,并进行路径压缩,提高查找效率。
边的选择与合并
- 在选择边时,确保不会形成圈,使用并查集的查找和合并操作。
- 更新最小生成树的边和权重,确保最小生成树的正确性。
- % MATLAB代码
- % 构造铁路距离赋权图
- function dist = floyd_warshall(A)
- n = size(A, 1);
- dist = A;
- dist(dist == 0) = inf;
- dist(1:n+1:end) = 0;
- for k = 1:n
- for i = 1:n
- for j = 1:n
- if dist(i, k) + dist(k, j) < dist(i, j)
- dist(i, j) = dist(i, k) + dist(k, j);
- end
- end
- end
- end
- end
-
- % 示例图的邻接矩阵
- A = [0 10 inf inf inf;
- 10 0 5 inf inf;
- inf 5 0 3 inf;
- inf inf 3 0 1;
- inf inf inf 1 0];
-
- % 计算最短路径
- dist = floyd_warshall(A);
-
- % 计算总费用的数学规划模型
- function total_cost = steel_pipeline_optimization(supplies, demands, cost_matrix)
- n_suppliers = length(supplies);
- n_demands = length(demands);
- total_cost = 0;
- for i = 1:n_suppliers
- for j = 1:n_demands
- total_cost = total_cost + supplies(i) * cost_matrix(i, j);
- end
- end
- end
-
- % 示例数据
- supplies = [100, 200, 150];
- demands = [50, 100, 200, 100];
- cost_matrix = [2, 4, 5, 6;
- 3, 2, 7, 4;
- 6, 5, 2, 3];
-
- % 计算总费用
- total_cost = steel_pipeline_optimization(supplies, demands, cost_matrix);
-
- % 显示结果
- disp('总费用:');
- disp(total_cost);
-
- % 可视化结果
- figure;
- imagesc(dist);
- colorbar;
- title('Floyd-Warshall最短路径距离矩阵');
- xlabel('目标节点');
- ylabel('起始节点');
Floyd-Warshall算法
function dist = floyd_warshall(A)
:定义Floyd-Warshall算法函数。n = size(A, 1)
:获取图中顶点的数量。dist = A
:初始化距离矩阵。dist(dist == 0) = inf
:将邻接矩阵中的0(无边)替换为无穷大。dist(1:n+1:end) = 0
:对角线上的元素设为0,表示自身到自身的距离为0。for k = 1:n, for i = 1:n, for j = 1:n
:三重循环更新距离矩阵。if dist(i, k) + dist(k, j) < dist(i, j)
:如果通过顶点k
的路径更短,则更新距离。dist(i, j) = dist(i, k) + dist(k, j)
:更新距离矩阵。
总费用的数学规划模型
function total_cost = steel_pipeline_optimization(supplies, demands, cost_matrix)
:定义总费用计算函数。n_suppliers = length(supplies)
:获取供应点数量。n_demands = length(demands)
:获取需求点数量。total_cost = 0
:初始化总费用。for i = 1:n_suppliers, for j = 1:n_demands
:双重循环遍历供应点和需求点。total_cost = total_cost + supplies(i) * cost_matrix(i, j)
:累加各供应点到各需求点的费用。
- import numpy as np
-
- def floyd_warshall(A):
- n = len(A)
- dist = np.array(A, dtype=float)
- dist[dist == 0] = np.inf
- np.fill_diagonal(dist, 0)
- for k in range(n):
- for i in range(n):
- for j in range(n):
- if dist[i, k] + dist[k, j] < dist[i, j]:
- dist[i, j] = dist[i, k] + dist[k, j]
- return dist
-
- # 示例图的邻接矩阵
- A = [
- [0, 10, float('inf'), float('inf'), float('inf')],
- [10, 0, 5, float('inf'), float('inf')],
- [float('inf'), 5, 0, 3, float('inf')],
- [float('inf'), float('inf'), 3, 0, 1],
- [float('inf'), float('inf'), float('inf'), 1, 0]
- ]
-
- # 计算最短路径
- dist = floyd_warshall(A)
-
- def steel_pipeline_optimization(supplies, demands, cost_matrix):
- total_cost = 0
- for i in range(len(supplies)):
- for j in range(len(demands)):
- total_cost += supplies[i] * cost_matrix[i][j]
- return total_cost
-
- # 示例数据
- supplies = [100, 200, 150]
- demands = [50, 100, 200, 100]
- cost_matrix = [
- [2, 4, 5, 6],
- [3, 2, 7, 4],
- [6, 5, 2, 3]
- ]
-
- # 计算总费用
- total_cost = steel_pipeline_optimization(supplies, demands, cost_matrix)
-
- # 显示结果
- print('总费用:', total_cost)
总费用: 7300
- % 创建图对象并可视化
- G = graph([1 2 2 3 3 4 4 5 5], [2 3 4 4 5 5 1 1 2], [10 20 30 40 50 60 70 80 90]);
-
- % 可视化图
- figure;
- plot(G, 'EdgeLabel', G.Edges.Weight);
- title('图的可视化');
-
- % 计算最短路径
- [start_node, end_node] = deal(1, 5);
- [dist, path] = shortestpath(G, start_node, end_node);
-
- % 显示最短路径
- disp('最短路径:');
- disp(path);
-
- % 计算最小生成树
- T = minspantree(G);
- figure;
- plot(T, 'EdgeLabel', T.Edges.Weight);
- title('最小生成树');
- 最短路径:
- 80
图与网络模型是解决复杂系统问题的重要工具,通过合理的算法和数学模型,可以有效地解决最短路径、最小生成树等问题。利用MATLAB和Python等工具,可以大大简化计算过程,提高工作效率。在实际应用中,图与网络模型广泛用于通信网络建设、物流运输规划等领域,具有重要的现实意义。希望这篇详细的博客总结能够帮助您理解和应用图与网络模型的基本概念、算法及其在实际问题中的应用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。