#头条创作挑战赛##python##AI编程助手##GPT4o到底可以干些啥#
更新:增加断环的节点优化建议。
本代码实现EXCEL XLSX格式的微波链路转换成拓扑图。并自动检测成环链路和重复链路,说明一下,程序完全是与GPT4o对话修改写成,这个AI写python代码相当强大,有点基础就可以实现相当复杂的功能,代码注释让AI可劲写,AI注释写的非常详细:
输入在E:\develop\save\links.xlsx文件,文件宏列标题只要含有SITE A和SITE B两列即可。
举例的数据输入格式如下:
LINK | SITE A | SITE B |
BA | B | A |
FC | F | C |
EB | E | B |
MD | M | D |
HD | H | D |
LA | L | A |
GD | G | D |
CA | C | A |
IF | I | F |
DA | D | A |
KJ | K | J |
JG | J | G |
XY | X | Y |
ffA | ff | A |
hhC | hh | C |
AK | A | K |
DA | D | A |
KD | K | D |
EL | E | L |
IA | I | A |
结果输出output.txt的检测结果,
Duplicate Links Count: 1
Duplicate Links: [('D', 'A')]
Cycle Count: 3
Cycles: [['B', 'A', 'L', 'E', 'B'], ['A', 'C', 'F', 'I', 'A'], ['D', 'G', 'J', 'K', 'D']]
输出的拓扑图:graph_1和graph_2,输出特意,将孤立的子图分别保存到不同的文件中,一个图就是一个链路。具体如下,可以调整links.xlsx得到不同的拓扑图,甚至可以直接用实际的微波链路文件之间运行。
断开后得TOPO(程序每个断开都会输出)贴最后的断环图(考虑分支最多和深度最小的优化断开)
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from collections import defaultdict
import matplotlib
matplotlib.use('Agg') # 使用Agg后端,不显示图像
def build_graph(links):
"""
构建图并检测重复链路
:param links: 链接列表,每个元素是一个包含两个节点的元组
:return: 图的字典表示和重复链路列表
"""
graph = defaultdict(list)
edges = set()
duplicate_links = []
for link in links:
site_a, site_b = link
# 检查是否为重复链路
if (site_a, site_b) in edges or (site_b, site_a) in edges:
duplicate_links.append((site_a, site_b))
else:
# 添加链路到图中
graph[site_a].append(site_b)
graph[site_b].append(site_a)
edges.add((site_a, site_b))
return graph, duplicate_links
def detect_cycles(graph):
"""
检测图中的成环链路
:param graph: 图的字典表示
:return: 成环链路列表
"""
visited = set()
parent = {}
cycles = []
def dfs(node, par, path):
"""
深度优先搜索检测成环链路
:param node: 当前节点
:param par: 父节点
:param path: 当前路径
:return: 是否找到成环链路
"""
visited.add(node)
parent[node] = par
path.append(node)
for neighbor in graph[node]:
if neighbor not in visited:
if dfs(neighbor, node, path):
return True
elif neighbor != par and neighbor in path:
# 找到成环链路
cycle = path[path.index(neighbor):] + [neighbor]
if cycle not in cycles: # 避免重复记录
cycles.append(cycle)
path.pop()
return False
for node in graph:
if node not in visited:
dfs(node, None, [])
return cycles
def draw_subgraph(subgraph, file_path):
"""
绘制子图并保存到文件
:param subgraph: 子图的字典表示
:param file_path: 保存文件路径
"""
G = nx.Graph()
for node, neighbors in subgraph.items():
for neighbor in neighbors:
G.add_edge(node, neighbor)
# 设置绘图布局和参数
pos = nx.spring_layout(G, k=0.3, iterations=50) # 调整k值和iterations参数
plt.figure(figsize=(16, 12)) # 调整图形大小
nx.draw(G, pos, with_labels=True, node_size=3000, node_color='skyblue', font_size=20, font_color='black',
font_weight='bold', edge_color='gray')
plt.title('Graph Visualization')
plt.savefig(file_path) # 保存图形到指定路径
plt.close() # 关闭图像,避免显示
def get_subgraphs(graph):
"""
获取图的所有子图
:param graph: 图的字典表示
:return: 子图列表
"""
G = nx.Graph(graph)
subgraphs = [G.subgraph(c).copy() for c in nx.connected_components(G)]
return subgraphs
def calculate_subtree_depth(graph, node, visited):
"""
计算节点的子树深度,包括其下挂站点的深度
:param graph: 图的字典表示
:param node: 当前节点
:param visited: 已访问节点集合
:return: 节点的子树深度
"""
visited.add(node)
depths = [calculate_subtree_depth(graph, neighbor, visited) for neighbor in graph[node] if neighbor not in visited]
visited.remove(node)
return 1 + max(depths, default=0)
def break_cycle(graph, cycle):
"""
在成环链路上分支最多且搜索深度最小的位置断开环
:param graph: 图的字典表示
:param cycle: 成环链路
:return: 断开环后的图
"""
min_combined_depth = float('inf')
node_to_remove = None
neighbor_to_remove = None
for i, node in enumerate(cycle):
for neighbor in graph[node]:
if neighbor in cycle:
# 计算断开(node, neighbor)后的综合深度
graph[node].remove(neighbor)
graph[neighbor].remove(node)
subtree_depth_node = calculate_subtree_depth(graph, node, set())
subtree_depth_neighbor = calculate_subtree_depth(graph, neighbor, set())
combined_depth = max(subtree_depth_node, subtree_depth_neighbor)
if combined_depth < min_combined_depth:
min_combined_depth = combined_depth
node_to_remove = node
neighbor_to_remove = neighbor
# 恢复连接
graph[node].append(neighbor)
graph[neighbor].append(node)
# 断开找到的最优连接
if node_to_remove and neighbor_to_remove:
graph[node_to_remove].remove(neighbor_to_remove)
graph[neighbor_to_remove].remove(node_to_remove)
return graph
# 从Excel文件读取数据,只读取"SITE A"和"SITE B"两列
file_path = "E:/develop/save/links.xlsx"
df = pd.read_excel(file_path, usecols=["SITE A", "SITE B"])
links = [tuple(x) for x in df.values]
# 构建图和检测重复链路
graph, duplicate_links = build_graph(links)
# 检测成环链路
cycles = detect_cycles(graph)
# 将结果输出到文本文件
output_file_path = "E:/develop/save/output.txt"
with open(output_file_path, "w") as f:
f.write(f"Duplicate Links Count: {len(duplicate_links)}\n")
f.write(f"Duplicate Links: {duplicate_links}\n")
f.write(f"Cycle Count: {len(cycles)}\n")
f.write(f"Cycles: {cycles}\n")
# 获取子图并分别保存
subgraphs = get_subgraphs(graph)
for i, subgraph in enumerate(subgraphs):
subgraph_dict = {node: list(subgraph.neighbors(node)) for node in subgraph.nodes()}
draw_subgraph(subgraph_dict, f"E:/develop/save/graph_{i + 1}.png")
# 断开成环链路并绘制图
for i, cycle in enumerate(cycles):
graph_copy = graph.copy()
graph_copy = break_cycle(graph_copy, cycle)
subgraphs = get_subgraphs(graph_copy)
for j, subgraph in enumerate(subgraphs):
subgraph_dict = {node: list(subgraph.neighbors(node)) for node in subgraph.nodes()}
draw_subgraph(subgraph_dict, f"E:/develop/save/graph_cycle_{i + 1}_subgraph_{j + 1}.png")
解释:
- 导入必要的库:pandas 用于读取 Excel 文件。networkx 用于图的操作和分析。matplotlib 用于绘制和保存图像。defaultdict 用于创建默认字典。
- build_graph 函数:构建图并检测重复链路。使用 defaultdict 创建图的字典表示。记录重复链路。
- detect_cycles 函数:使用深度优先搜索(DFS)检测图中的成环链路。避免重复记录成环链路。
- draw_subgraph 函数:绘制子图并保存到文件。使用 Agg 后端避免显示图像。
- get_subgraphs 函数:获取图的所有子图。
- 读取 Excel 文件:只读取 "SITE A" 和 "SITE B" 两列数据。
- 构建图和检测重复链路:使用 build_graph 函数构建图并检测重复链路。
- 检测成环链路:使用 detect_cycles 函数检测成环链路。
- 将结果输出到文本文件:将重复链路和成环链路的结果输出到指定的文本文件中。
- 获取子图并分别保存:使用 get_subgraphs 函数获取子图,并使用 draw_subgraph 函数绘制并保存每个子图。