【数学建模】——前沿图与网络模型:新时代算法解析与应用

news2024/9/22 11:37:51

目录

1.图与网络的基本概念

1. 无向图和有向图

2. 简单图、完全图、赋权图

3. 顶点的度

4. 子图与图的连通性

2.图的矩阵表示

1. 关联矩阵

2. 邻接矩阵

3.最短路问题

1.Dijkstra 算法

2.Floyd 算法

4.最小生成树问题

1.Kruskal 算法

2.Prim 算法

5.着色问题

6.旅行商问题

近似算法

7.网络最大流问题

Ford-Fulkerson 算法

8.计划评审方法与关键路径

9.钢管订购和运输

总结


 

ce6fbd68767d465bbe94b775b8b811db.png

731bd47804784fa2897220a90a387b28.gif

专栏:数学建模学习笔记

上一篇:【MATLAB】和【Python】进行【图与网络模型】的高级应用与分析】

本篇是对上一篇的升华,进一步学习

1.图与网络的基本概念

1. 无向图和有向图

根据PPT内容,我们知道图的基本概念包括无向图和有向图。

  • 无向图:边没有方向,表示为 (u, v) = (v, u)。
  • 有向图:边有方向,表示为 (u, v) ≠ (v, u)。

PPT中的示例图可以用以下代码进行可视化:

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()

代码解析

  • networkx库用于创建和操作图。
  • matplotlib库用于绘图。
  • nx.Graph()创建无向图,nx.DiGraph()创建有向图。
  • add_edges_from()方法添加边。
  • nx.draw()方法绘制图形。

2. 简单图、完全图、赋权图

  • 简单图:没有自环和重边的图。
  • 完全图:任意两个不同顶点之间都有边的图。
  • 赋权图:边上有权值的图。

PPT中的示例图可以用以下代码进行可视化:

import networkx as nx
import matplotlib.pyplot as plt
# 简单图
G_simple = nx.Graph()
G_simple.add_edges_from([(1, 2), (2, 3), (3, 4), (4, 1)])
plt.figure(figsize=(8, 6))
plt.title("Simple Graph")
nx.draw(G_simple, with_labels=True, node_color='lightgreen', node_size=2000, edge_color='black', linewidths=1, font_size=15)
plt.show()

# 完全图
G_complete = nx.complete_graph(5)
plt.figure(figsize=(8, 6))
plt.title("Complete Graph")
nx.draw(G_complete, with_labels=True, node_color='lightcoral', node_size=2000, edge_color='black', linewidths=1, font_size=15)
plt.show()

# 赋权图
G_weighted = nx.Graph()
G_weighted.add_weighted_edges_from([(1, 2, 0.6), (1, 3, 0.2), (2, 3, 0.8), (2, 4, 0.4)])
plt.figure(figsize=(8, 6))
plt.title("Weighted Graph")
pos = nx.spring_layout(G_weighted)
nx.draw(G_weighted, pos, with_labels=True, node_color='lightblue', node_size=2000, edge_color='black', linewidths=1, font_size=15)
labels = nx.get_edge_attributes(G_weighted, 'weight')
nx.draw_networkx_edge_labels(G_weighted, pos, edge_labels=labels)
plt.show()

 

代码解析

  • nx.complete_graph()创建完全图。
  • nx.add_weighted_edges_from()添加有权值的边。
  • nx.spring_layout()设置图的布局。
  • nx.draw_networkx_edge_labels()显示边的权值。

3. 顶点的度

  • 顶点的度:连接该顶点的边的数目。

PPT中的示例可以用以下代码展示顶点的度:

import networkx as nx
import matplotlib.pyplot as plt

# 计算无向图的顶点度
G_undirected = nx.Graph()
G_undirected.add_edges_from([(1, 2), (1, 3), (2, 4), (3, 4)])
G_undirected_degree = G_undirected.degree()
plt.figure(figsize=(8, 6))
plt.title("Undirected Graph - Node Degree")
nx.draw(G_undirected, with_labels=True, node_color='skyblue', node_size=[v * 1000 for k, v in G_undirected_degree], edge_color='black', linewidths=1, font_size=15)
plt.show()

# 计算有向图的顶点入度和出度
G_directed = nx.DiGraph()
G_directed.add_edges_from([(1, 2), (1, 3), (2, 4), (3, 4)])
G_directed_in_degree = G_directed.in_degree()
G_directed_out_degree = G_directed.out_degree()
plt.figure(figsize=(8, 6))
plt.title("Directed Graph - Node In-Degree")
nx.draw(G_directed, with_labels=True, node_color='skyblue', node_size=[v * 1000 for k, v in G_directed_in_degree], edge_color='black', arrows=True, linewidths=1, font_size=15)
plt.show()

plt.figure(figsize=(8, 6))
plt.title("Directed Graph - Node Out-Degree")
nx.draw(G_directed, with_labels=True, node_color='skyblue', node_size=[v * 1000 for k, v in G_directed_out_degree], edge_color='black', arrows=True, linewidths=1, font_size=15)
plt.show()

代码解析

  • degree()计算无向图顶点的度。
  • in_degree()计算有向图顶点的入度。
  • out_degree()计算有向图顶点的出度。

 

4. 子图与图的连通性

  • 子图:原图的部分顶点和边组成的图。
  • 连通图:任意两个顶点之间都有路径相连的图。

PPT中的示例可以用以下代码展示子图和连通性:

import networkx as nx
import matplotlib.pyplot as plt

# 子图示例
G_undirected = nx.Graph()
G_undirected.add_edges_from([(1, 2), (1, 3), (2, 4), (3, 4)])
subgraph_nodes = [1, 2, 3]
G_subgraph = G_undirected.subgraph(subgraph_nodes)
plt.figure(figsize=(8, 6))
plt.title("Subgraph")
nx.draw(G_subgraph, with_labels=True, node_color='yellow', node_size=2000, edge_color='black', linewidths=1, font_size=15)
plt.show()

# 连通图示例
G_connected = nx.cycle_graph(5)
plt.figure(figsize=(8, 6))
plt.title("Connected Graph")
nx.draw(G_connected, with_labels=True, node_color='lightblue', node_size=2000, edge_color='black', linewidths=1, font_size=15)
plt.show()

# 不连通图示例
G_disconnected = nx.Graph()
G_disconnected.add_edges_from([(1, 2), (3, 4)])
plt.figure(figsize=(8, 6))
plt.title("Disconnected Graph")
nx.draw(G_disconnected, with_labels=True, node_color='lightblue', node_size=2000, edge_color='black', linewidths=1, font_size=15)
plt.show()

代码解析

  • subgraph()生成子图。
  • cycle_graph()创建连通图(环图)。
  • 添加孤立的边以生成不连通图。

 

2.图的矩阵表示

1. 关联矩阵

关联矩阵用于表示图中顶点与边之间的关系。在无向图中,关联矩阵是一个 |V| × |E| 的矩阵,其中 |V| 是顶点数,|E| 是边数。矩阵中的元素 a[i][j] 表示顶点 i 是否与边 j 相连,如果相连则为 1,否则为 0。在有向图中,a[i][j] 为 -1 表示顶点 i 是边 j 的起点,为 1 表示顶点 i 是边 j 的终点。

根据PPT的描述,我们可以用以下代码展示关联矩阵:

import networkx as nx
import numpy as np

# 无向图
G_undirected = nx.Graph()
G_undirected.add_edges_from([(1, 2), (1, 3), (2, 4), (3, 4)])
G_undirected_adj = nx.incidence_matrix(G_undirected).todense()
print("无向图的关联矩阵:\n", G_undirected_adj)

# 有向图
G_directed = nx.DiGraph()
G_directed.add_edges_from([(1, 2), (1, 3), (2, 4), (3, 4)])
G_directed_adj = nx.incidence_matrix(G_directed, oriented=True).todense()
print("有向图的关联矩阵:\n", G_directed_adj)

代码解析

  • incidence_matrix()计算关联矩阵。
  • oriented=True用于有向图。
无向图的关联矩阵:
 [[1. 1. 0. 0.]
 [1. 0. 1. 0.]
 [0. 1. 0. 1.]
 [0. 0. 1. 1.]]
有向图的关联矩阵:
 [[-1. -1.  0.  0.]
 [ 1.  0. -1.  0.]
 [ 0.  1.  0. -1.]
 [ 0.  0.  1.  1.]]

2. 邻接矩阵

邻接矩阵用于表示顶点之间是否直接相连。对于一个有 n 个顶点的图,邻接矩阵是一个 n × n 的矩阵。对于无向图,如果顶点 i 与顶点 j 之间有边相连,则 a[i][j] = 1,否则 a[i][j] = 0。在赋权图中,a[i][j] 表示顶点 i 和顶点 j 之间边的权值,如果没有边则为 0 或无穷大。

根据PPT的描述,我们可以用以下代码展示邻接矩阵:

import networkx as nx

# 无向图
G_undirected = nx.Graph()
G_undirected.add_edges_from([(1, 2), (1, 3), (2, 4), (3, 4)])
G_undirected_adj_matrix = nx.adjacency_matrix(G_undirected).todense()
print("无向图的邻接矩阵:\n", G_undirected_adj_matrix)

# 有向图
G_directed = nx.DiGraph()
G_directed.add_edges_from([(1, 2), (1, 3), (2, 4), (3, 4)])
G_directed_adj_matrix = nx.adjacency_matrix(G_directed).todense()
print("有向图的邻接矩阵:\n", G_directed_adj_matrix)

代码解析

  • adjacency_matrix()计算邻接矩阵。
无向图的邻接矩阵:
 [[0 1 1 0]
 [1 0 0 1]
 [1 0 0 1]
 [0 1 1 0]]
有向图的邻接矩阵:
 [[0 1 1 0]
 [0 0 0 1]
 [0 0 0 1]
 [0 0 0 0]]

 

3.最短路问题

最短路问题是指在赋权图中,找到从源点到目标点的最短路径。常见的算法有 Dijkstra 算法和 Floyd 算法。

1.Dijkstra 算法

Dijkstra 算法用于求解单源最短路径问题,适用于所有边权值为非负的图。算法的基本思想是通过贪心策略,每次选择距离起点最近的未访问顶点,并更新其邻接顶点的距离。具体步骤如下:

  1. 初始化源点到自身的距离为 0,其余顶点的距离为无穷大。
  2. 将所有顶点加入未访问集合。
  3. 从未访问集合中选择距离起点最近的顶点 u,标记 u 为已访问。
  4. 对于 u 的每个邻接顶点 v,如果 u 到 v 的距离加上 u 到起点的距离小于 v 到起点的当前距离,则更新 v 的距离。
  5. 重复步骤 3 和 4,直到所有顶点都被访问。

Dijkstra 算法的时间复杂度为 O(V^2),对于稠密图比较适用。如果使用优先队列进行优化,时间复杂度可以降到 O(E log V)。

PPT中的示例可以用以下代码展示Dijkstra算法:

import heapq

def dijkstra(graph, start):
    pq = [(0, start)]
    distances = {vertex: float('infinity') for vertex in graph}
    distances[start] = 0

    while pq:
        current_distance, current_vertex = heapq.heappop(pq)

        if current_distance > distances[current_vertex]:
            continue

        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight

            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))

    return distances

graph = {
    'A': {'B': 1, 'C': 4},
    'B': {'A': 1, 'C': 2, 'D': 5},
    'C': {'A': 4, 'B': 2, 'D': 1},
    'D': {'B': 5, 'C': 1}
}

distances = dijkstra(graph, 'A')
print("Dijkstra's Algorithm Output:", distances)

代码解析

  • heapq用于实现优先队列。
  • dijkstra()函数实现了Dijkstra算法。
  • distances存储每个顶点的最短距离。

Dijkstra's Algorithm Output: {'A': 0, 'B': 1, 'C': 3, 'D': 4} 

2.Floyd 算法

Floyd 算法用于求解任意两点间的最短路径问题,适用于所有边权值为非负的图。算法的基本思想是通过动态规划,每次考虑加入一个中间顶点来更新最短路径。具体步骤如下:

  1. 初始化一个距离矩阵,直接使用图的邻接矩阵表示顶点之间的距离。
  2. 对于每个顶点 k,更新所有顶点对 (i, j) 的距离。如果 i 到 j 的距离通过顶点 k 更短,则更新距离矩阵。
  3. 重复上述步骤,直到考虑完所有顶点。

Floyd 算法的时间复杂度为 O(V^3),适用于稀疏图和需要频繁查询任意两点最短路径的情况。

PPT中的示例可以用以下代码展示Floyd算法:

def floyd_warshall(graph):
    nodes = list(graph.keys())
    distances = {node: {node2: float('infinity') for node2 in nodes} for node in nodes}

    for node in nodes:
        distances[node][node] = 0

    for node in graph:
        for neighbor in graph[node]:
            distances[node][neighbor] = graph[node][neighbor]

    for k in nodes:
        for i in nodes:
            for j in nodes:
                if distances[i][j] > distances[i][k] + distances[k][j]:
                    distances[i][j] = distances[i][k] + distances[k][j]

    return distances

graph = {
    'A': {'B': 1, 'C': 4},
    'B': {'A': 1, 'C': 2, 'D': 5},
    'C': {'A': 4, 'B': 2, 'D': 1},
    'D': {'B': 5, 'C': 1}
}

distances = floyd_warshall(graph)
print("Floyd-Warshall Algorithm Output:")
for row in distances:
    print(row, distances[row])

代码解析

  • floyd_warshall()函数实现了Floyd算法。
  • distances存储每对顶点之间的最短距离。

Floyd-Warshall Algorithm Output:
A {'A': 0, 'B': 1, 'C': 3, 'D': 4}
B {'A': 1, 'B': 0, 'C': 2, 'D': 3}
C {'A': 3, 'B': 2, 'C': 0, 'D': 1}
D {'A': 4, 'B': 3, 'C': 1, 'D': 0} 

4.最小生成树问题

最小生成树问题是指在一个连通图中,找到一棵包含所有顶点且边权值之和最小的树。常见的算法有 Kruskal 算法和 Prim 算法。

1.Kruskal 算法

Kruskal 算法是一种贪心算法,主要思想是每次选择权值最小的边,并保证不形成圈,直到构建出最小生成树。具体步骤如下:

  1. 将图中的所有边按权值从小到大排序。
  2. 初始化一个空集合,用于存放最小生成树的边。
  3. 从权值最小的边开始,依次选择边,如果选择的边与当前集合中的边不形成圈,则将该边加入集合。
  4. 重复步骤 3,直到集合中包含 n-1 条边,其中 n 是图的顶点数。

Kruskal 算法的时间复杂度为 O(E log E),适用于边数较少的稀疏图。

PPT中的示例可以用以下代码展示Kruskal算法:

class DisjointSet:
    def __init__(self, vertices):
        self.parent = {v: v for v in vertices}
        self.rank = {v: 0 for v in vertices}

    def find(self, item):
        if self.parent[item] != item:
            self.parent[item] = self.find(self.parent[item])
        return self.parent[item]

    def union(self, set1, set2):
        root1 = self.find(set1)
        root2 = self.find(set2)

        if root1 != root2:
            if self.rank[root1] > self.rank[root2]:
                self.parent[root2] = root1
            else:
                self.parent[root1] = root2
                if self.rank[root1] == self.rank[root2]:
                    self.rank[root2] += 1

def kruskal(graph):
    edges = [(weight, u, v) for u in graph for v, weight in graph[u].items()]
    edges.sort()
    ds = DisjointSet(graph.keys())
    mst = []

    for edge in edges:
        weight, u, v = edge
        if ds.find(u) != ds.find(v):
            ds.union(u, v)
            mst.append((u, v, weight))

    return mst

graph = {
    'A': {'B': 1, 'C': 4},
    'B': {'A': 1, 'C': 2, 'D': 5},
    'C': {'A': 4, 'B': 2, 'D': 1},
    'D': {'B': 5, 'C': 1}
}

mst = kruskal(graph)
print("Kruskal's Algorithm Output:", mst)

代码解析

  • DisjointSet类用于实现并查集,以检测是否形成环。
  • kruskal()函数实现了Kruskal算法。
  • edges存储图中的所有边并按权值排序。
  • mst存储最小生成树的边。

Kruskal's Algorithm Output: [('A', 'B', 1), ('C', 'D', 1), ('B', 'C', 2)] 

2.Prim 算法

Prim 算法也是一种贪心算法,主要思想是从一个顶点开始,每次选择连接已选顶点集合和未选顶点集合的最小权值边,直至所有顶点都被选中。具体步骤如下:

  1. 初始化一个顶点集合,包括图中的任意一个顶点。
  2. 初始化一个空集合,用于存放最小生成树的边。
  3. 从顶点集合中选择一条连接已选顶点和未选顶点的最小权值边,将该边和边的终点加入集合。
  4. 重复步骤 3,直到所有顶点都被选中。

Prim 算法的时间复杂度为 O(V^2),适用于顶点数较少的稠密图。如果使用优先队列进行优化,时间复杂度可以降到 O(E log V)。

PPT中的示例可以用以下代码展示Prim算法:

import heapq

def prim(graph, start):
    mst = []
    visited = {start}
    edges = [(weight, start, to) for to, weight in graph[start].items()]
    heapq.heapify(edges)

    while edges:
        weight, frm, to = heapq.heappop(edges)
        if to not in visited:
            visited.add(to)
            mst.append((frm, to, weight))

            for to_next, weight in graph[to].items():
                if to_next not in visited:
                    heapq.heappush(edges, (weight, to, to_next))

    return mst

graph = {
    'A': {'B': 1, 'C': 4},
    'B': {'A': 1, 'C': 2, 'D': 5},
    'C': {'A': 4, 'B': 2, 'D': 1},
    'D': {'B': 5, 'C': 1}
}

mst = prim(graph, 'A')
print("Prim's Algorithm Output:", mst)

代码解析

  • prim()函数实现了Prim算法。
  • visited存储已选顶点。
  • edges存储连接已选顶点和未选顶点的边。

Prim's Algorithm Output: [('A', 'B', 1), ('B', 'C', 2), ('C', 'D', 1)] 

5.着色问题

图着色是指将图的顶点涂上不同的颜色,使得相邻顶点颜色不同。图着色问题的目的是使用尽可能少的颜色。图着色在调度问题、地图着色等实际问题中有广泛应用。

PPT中的示例可以用以下代码展示图着色:

import networkx as nx
import matplotlib.pyplot as plt

def greedy_coloring(graph):
    color_map = {}
    for node in graph:
        available_colors = set(range(len(graph)))
        for neighbor in graph[node]:
            if neighbor in color_map:
                available_colors.discard(color_map[neighbor])
        color_map[node] = min(available_colors)
    return color_map

graph = {
    'A': ['B', 'C'],
    'B': ['A', 'C', 'D'],
    'C': ['A', 'B', 'D'],
    'D': ['B', 'C']
}

coloring = greedy_coloring(graph)
print("Graph Coloring Output:", coloring)

# 可视化图着色
G_coloring = nx.Graph(graph)
colors = [coloring[node] for node in G_coloring.nodes()]
plt.figure(figsize=(8, 6))
plt.title("Graph Coloring")
nx.draw(G_coloring, with_labels=True, node_color=colors, node_size=2000, cmap=plt.cm.rainbow, edge_color='black', linewidths=1, font_size=15)
plt.show()

代码解析

  • greedy_coloring()函数实现了贪心着色算法。
  • color_map存储每个顶点的颜色。
  • available_colors存储每个顶点可用的颜色。

Graph Coloring Output: {'A': 0, 'B': 1, 'C': 2, 'D': 0} 

 

6.旅行商问题

旅行商问题是指在一组城市中找出一条最短路径,使得旅行商访问每个城市一次并回到起点。这是一个经典的 NP 完全问题,求解方法包括近似算法和启发式算法。

近似算法

由于旅行商问题的复杂性,通常使用近似算法来求解,如贪心算法、动态规划等。贪心算法通过每次选择距离当前城市最近的未访问城市来构建路径,而动态规划通过记忆化搜索来避免重复计算。

PPT中的示例可以用以下代码展示旅行商问题:

import itertools

def tsp_brute_force(graph):
    nodes = list(graph.keys())
    shortest_path = None
    min_cost = float('infinity')

    for perm in itertools.permutations(nodes):
        cost = 0
        for i in range(len(perm) - 1):
            cost += graph[perm[i]][perm[i + 1]]
        cost += graph[perm[-1]][perm[0]]

        if cost < min_cost:
            min_cost = cost
            shortest_path = perm

    return shortest_path, min_cost

graph = {
    'A': {'B': 10, 'C': 15, 'D': 20},
    'B': {'A': 10, 'C': 35, 'D': 25},
    'C': {'A': 15, 'B': 35, 'D': 30},
    'D': {'A': 20, 'B': 25, 'C': 30}
}

path, cost = tsp_brute_force(graph)
print("TSP Brute Force Output:", path, "with cost", cost)

代码解析

  • itertools.permutations()生成所有可能的路径。
  • tsp_brute_force()函数实现了暴力求解旅行商问题。
  • shortest_path存储最短路径,min_cost存储最小成本。

TSP Brute Force Output: ('A', 'B', 'D', 'C') with cost 80 

7.网络最大流问题

网络最大流问题是指在一个流网络中,找到从源点到汇点的最大流量路径。常见的算法有 Ford-Fulkerson 算法。

Ford-Fulkerson 算法

Ford-Fulkerson 算法通过反复寻找增广路径来增加流量,直到找不到增广路径为止。具体步骤如下:

  1. 初始化流量为 0。
  2. 使用深度优先搜索或广度优先搜索找到一条增广路径。
  3. 更新增广路径上的流量,增加路径上的最小残余容量。
  4. 重复步骤 2 和 3,直到找不到增广路径。

Ford-Fulkerson 算法的时间复杂度为 O(E |f|),其中 E 是边数,|f| 是最大流量的值。

PPT中的示例可以用以下代码展示Ford-Fulkerson算法:

from collections import deque

def bfs(C, F, source, sink):
    queue = deque([source])
    paths = {source: []}
    while queue:
        u = queue.popleft()
        for v in C[u]:
            if C[u][v] - F[u][v] > 0 and v not in paths:
                paths[v] = paths[u] + [(u, v)]
                if v == sink:
                    return paths[v]
                queue.append(v)
    return None

def ford_fulkerson(graph, source, sink):
    C = {u: {} for u in graph}
    for u in graph:
        for v, capacity in graph[u].items():
            C[u][v] = capacity
            if v not in C:
                C[v] = {}
            C[v][u] = 0

    F = {u: {v: 0 for v in C[u]} for u in C}
    max_flow = 0

    while True:
        path = bfs(C, F, source, sink)
        if not path:
            break
        flow = min(C[u][v] - F[u][v] for u, v in path)
        for u, v in path:
            F[u][v] += flow
            F[v][u] -= flow
        max_flow += flow

    return max_flow

graph = {
    'A': {'B': 3, 'C': 3},
    'B': {'C': 2, 'D': 3},
    'C': {'D': 2, 'E': 2},
    'D': {'F': 2},
    'E': {'D': 1, 'F': 3},
    'F': {}
}

max_flow = ford_fulkerson(graph, 'A', 'F')
print("Ford-Fulkerson Algorithm Output:", max_flow)

代码解析

  • bfs()函数实现广度优先搜索,找到增广路径。
  • ford_fulkerson()函数实现Ford-Fulkerson算法。
  • C存储容量,F存储流量。
  • max_flow存储最大流量。

Ford-Fulkerson Algorithm Output: 4 

8.计划评审方法与关键路径

关键路径法(CPM)用于项目管理中,通过计算项目中各任务的最早开始时间和最晚完成时间,找出影响项目工期的关键路径。关键路径是指项目中耗时最长的路径,决定了项目的最短完成时间。

PPT中的示例可以用以下代码展示关键路径法:

def critical_path_method(tasks):
    longest_path = []
    max_duration = 0
    for task in tasks:
        if task['duration'] > max_duration:
            max_duration = task['duration']
            longest_path = [task['name']]
        elif task['duration'] == max_duration:
            longest_path.append(task['name'])
    return longest_path, max_duration

tasks = [
    {'name': 'A', 'duration': 3},
    {'name': 'B', 'duration': 2},
    {'name': 'C', 'duration': 4},
    {'name': 'D', 'duration': 1},
    {'name': 'E', 'duration': 3}
]

path, duration = critical_path_method(tasks)
print("Critical Path Method Output:", path, "with duration", duration)

代码解析

  • critical_path_method()函数计算关键路径。
  • tasks存储每个任务的名称和持续时间。
  • longest_path存储关键路径,max_duration存储最长持续时间。

Critical Path Method Output: ['C'] with duration 4 

9.钢管订购和运输

钢管订购和运输问题涉及从多个供应点向需求点运输钢管,要求最小化运输和铺设费用。具体步骤包括:

  1. 构建运费矩阵,计算从各个供应点到各个需求点的运输费用。
  2. 构建数学规划模型,设定目标函数为总费用最小化。
  3. 使用优化算法求解模型,确定最佳的订购和运输方案。

PPT中的示例可以用以下代码展示钢管订购和运输问题:

from scipy.optimize import linprog

c = [20, 30, 10, 40, 30, 20, 10, 20, 10]  # 费用系数
A_eq = [
    [1, 1, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 1, 0, 1, 1, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 1, 1, 1]
]  # 约束条件
b_eq = [200, 150, 100]  # 需求
bounds = [(0, float('inf'))] * len(c)  # 变量边界

res = linprog(c, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method='highs')
print("Optimal value:", res.fun)
print("Optimal solution:", res.x)

代码解析

  • linprog()函数求解线性规划问题。
  • c表示费用系数,A_eq表示约束条件,b_eq表示需求,bounds表示变量边界。
  • res.fun返回最优值,res.x返回最优解。

Optimal value: 6500.0
Optimal solution: [200.   0. 150.   0.   0.   0. 100.   0.   0.] 

总结

图与网络模型的基本概念、矩阵表示、最短路径、最小生成树、着色问题、旅行商问题、网络最大流问题及关键路径法等主题,结合PPT内容和Python代码实例,深入解析了每个主题的核心算法和应用场景,提供了可视化代码和图形展示,以便更好地理解和应用这些重要的图论算法。

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

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

相关文章

【AI大模型】程序员AI的未来——Copilot还是Claude3.5 Sonnet?

近期&#xff0c;Anthropic发布了Claude 3.5 的“大杯”模型 —— Claude 3.5 Sonnet&#xff01; 这次发布的 Sonnet 代表意大利的“十四行诗”&#xff0c;结构复杂&#xff0c;在智能水平、功能多样性和处理能力上都有所提升&#xff0c;能够应对更复杂的认知任务&#xff…

进程与进程函数

目录 进程与程序 1.1进程是什么 1.2程序&#xff0c;进程之间的关系 1.3进程的生存环境 1.4进程的状态转换 1.5关于内核层与用户层 1.6保存和恢复处理器现场 进程原语 2.1fork() ​编辑 2.1.1父子进程的继承 2.1.2父子进程共享fork()栈帧 2.1.3打印进程id和父进程i…

【OpenREALM学习笔记:14】单目视觉SLAM方法在UAV影像上重建三维地形的思考

最近在学习SLAM技术与测绘三维影像重建的相关知识&#xff0c;结合自己的感受&#xff0c;撰写一下对于单目视觉SLAM利用无人机影像重建三维地形的一些看法。 1. 单目视觉SLAM系统在三维地形重建中所面临的挑战有哪些&#xff1f; 单目视觉SLAM众所周知的一个问题是&#xff…

C# 委托函数 delegate

在C#中&#xff0c;委托&#xff08;Delegate&#xff09;是一种特殊的类型&#xff0c;它可以持有对方法的引用。 委托是实现事件的基础。事件本质上是多播委托&#xff0c;允许多个方法被触发 委托允许你将方法作为参数传递给其他方法&#xff0c;或者将方法作为返回值从方法…

feed流(投喂)

1、拉模式&#xff1a; 优缺点&#xff1a;节省空间&#xff0c;只存一份&#xff0c;赵六在需要的时候直接去读。延迟高&#xff0c;耗时长。如果关注的人多的话&#xff0c;就会一次性拉取的很大&#xff0c;造成拥塞。 2、推模式 优缺点&#xff1a;延迟低&#xff0c;耗时少…

嵌入式C++、STM32、树莓派4B、OpenCV、TensorFlow/Keras深度学习:基于边缘计算的实时异常行为识别

1. 项目概述 随着物联网和人工智能技术的发展,智能家居安全系统越来越受到人们的关注。本项目旨在设计并实现一套基于边缘计算的智能家居安全系统,利用STM32微控制器和树莓派等边缘设备,实时分析摄像头数据,识别异常行为(如入侵、跌倒等),并及时发出警报,提高家庭安全性。 系…

内存卡损坏读不出怎么修复?内存卡数据恢复的7个方法请收好!

当面对内存卡损坏、无法读取数据的困扰时&#xff0c;许多人会感到焦虑和困惑。尤其是当这些卡中存储着珍贵的照片、视频或文件时&#xff0c;这种困扰更显得令人不安。您是否也曾因内存卡损坏而无法显示照片或遭遇需要格式化的提示而感到困扰&#xff1f;在我们日常的生活中&a…

power bi文本,截取及查找函数

power bi文本,截取及查找函数 1. 文本函数1.concatenate函数2. exact 函数3. find函数4. search函数 2. 截取函数1. fixed 函数2. 大小写转换3. trim函数4.rept函数5. replace 函数6. substitute函数 3. 查找匹配函数1 contains函数2. treatas 函数3. ContainsString函数4. Con…

GPT模型为什么能生成有意义的文本

GPT模型的底层&#xff0c;其实是谷歌团队推出的Transformer模型。但是在GPT-3出现之前&#xff0c;大家一直对它没有多少了解。直到它的参数数量突破1750亿个的时候&#xff0c;它才建立起一个庞大的神经网络&#xff0c;这个神经网络最突出的特点是大数据、大模型和大计算。其…

宠物经济纵深观察:口红效应显著,呈可持续发展态势

七月以来&#xff0c;全国各地陆续开启高温模式。和人一样&#xff0c;“毛孩子们”同样也难耐高温&#xff0c;由此&#xff0c;围绕猫猫狗狗的“宠物经济”迅速升温&#xff0c;宠物冰垫、宠物饮水机、宠物烘干机......一系列宠物单品掀起夏日消费热潮。 就在几天前&#xf…

mysql的主从复制和读写分离:

mysql的主从复制和读写分离&#xff1a; 主从复制 面试必问&#xff1a;主从复制的原理 主从复制的模式&#xff1a; 1、mysql的默认模式&#xff1a; 异步模式 主库在更新完事务之后会立即把结果返回给从服务器&#xff0c;并不关心从库是否接受到&#xff0c;以及从库是…

汽车研发项目管理系统排行榜:五大热门汽车项目管理系统推荐

汽车研发项目管理软件在汽车制造行业中扮演着至关重要的角色&#xff0c;本文介绍了五款在汽车及零部件领域专业的项目管理软件。 一、 奥博思 PowerProject 企业级项目管理系统 奥博思 PowerProject 项目管理系统&#xff08;支持项目管理、项目集管理、项目组合管理三位一体…

LLM之RAG理论(十二)| RAG和Graph RAG对比

最近Graph RAG非常火&#xff0c;它来自微软的一篇论文《From Local to Global: A Graph RAG Approach to Query-Focused Summarization》&#xff0c;论文地址&#xff1a;https://arxiv.org/pdf/2404.16130。本文将对RAG 和 Graph RAG在架构和成本方面做简要分析。 一、RAG …

家里灰尘多又不想打扫。教你一招,省时省事,除尘很轻松

出差半个月前&#xff0c;我住在新装修的房子里两周。在新餐桌上铺了一块桌布&#xff0c;结果一周后布上就积了一层灰尘。而且&#xff0c;那些夜里&#xff0c;我经常听到妻子剧烈咳嗽&#xff0c;令人担心。她有中度肺部疾病&#xff0c;平时非常注意卫生&#xff0c;每天都…

mysql高阶语句:

mysql高阶语句&#xff1a; 高级语法的查询语句&#xff1a; select * from 表名 where limitsdistinct 去重查询like 模糊查询 排序语法&#xff1a;关键字排序 升序和降序 默认的排序方式就是升序 升序&#xff1a;ASC 配合order by语法 select * from 表名…

大模型应用—大模型赋能搜索

大模型赋能搜索 AI正在改变搜索体验,使其对我们来说更加智能、个性化和高效。 你可能会想,“但是谷歌已经足够好了!”首先,谷歌的搜索相关性和个性化是有代价的,那么跨不同媒体类型的搜索呢?对于最相关的信息格式,甚至是自动化某些任务,比如抓取网站、索引内容和搜索…

因为很会用工具,拿下了很多客户!

作为一名想要得到更多业绩的打工人&#xff0c;能提高工作效率的工具一定要拥有&#xff01; 今天&#xff0c;就给大家分享一个职场必备的提效神器&#xff0c;一起来看看它都有哪些功能吧&#xff01; 1、多渠道客源 它可以从多个渠道去获取你想要的客户资源&#xff0c;无…

CSS画边框线带有渐变线和流光边框实例

流光边框css流光边框动画效果_哔哩哔哩_bilibili流光边框css流光边框动画效果_哔哩哔哩_bilibili纯CSS写一个动态流水灯边框的效果&#xff5e;_哔哩哔哩_bilibili荧光边框CSS 动画发光渐变边框特效_哔哩哔哩_bilibili [data-v-25d37a3a] .flow-dialog-custom {background-col…

简单使用SpringMVC写一个图书管理系统的登入功能和图书展示功能

准备好前端的代码 这里已经准备好了前端的代码&#xff0c;这里仅仅简单的介绍登入功能&#xff0c;和展示图书列表的功能。 如图&#xff1a; 如上图所示&#xff0c;这里的前端代码还是比较多的&#xff0c;在这里我介绍&#xff0c;login.html还有book_list.html这两个。 l…

springboot智慧草莓基地管理系统--论文源码调试讲解

3 系统分析 当用户确定开发一款程序时&#xff0c;是需要遵循下面的顺序进行工作&#xff0c;概括为&#xff1a;系统分析-->系统设计-->系统开发-->系统测试&#xff0c;无论这个过程是否有变更或者迭代&#xff0c;都是按照这样的顺序开展工作的。系统分析就是分析…