You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于最小生成树(MST)分析图结构并提取所有主轨迹

基于MST提取主轨迹的实现方案

核心逻辑

最小生成树是无环连通图,主轨迹拆分遵循以下规则:

  • 轨迹的端点都是图中度为1的叶子节点(仅和1个其他节点相连)
  • 轨迹的拆分交汇点是度大于2的分叉节点(和3个及以上其他节点相连)
  • 从每个叶子节点出发沿边遍历,遇到分叉节点或其他叶子节点时终止,即可得到独立的轨迹段,自动去重重复边即可避免重复输出
  • 特殊兼容无分叉的单链MST场景(所有节点串成一条线,此时无度大于2的节点,直接返回整条连通路径)

完整实现代码

from scipy.sparse.csgraph import minimum_spanning_tree
from scipy.spatial.distance import cdist
import pandas as pd
import numpy as np
from collections import defaultdict

def extract_main_tracks(df: pd.DataFrame) -> list[list]:
    """
    输入:索引为节点名称、列为坐标值的DataFrame
    输出:拆分后的主轨迹列表,每个子列表为一条独立轨迹的节点顺序
    """
    node_list = df.index.tolist()
    # 计算欧氏距离矩阵与MST
    dist_mat = cdist(df.values, df.values)
    mst_res = minimum_spanning_tree(dist_mat)
    mst_arr = mst_res.toarray()

    # 构建无向邻接表
    adj_table = defaultdict(list)
    edge_coords = np.argwhere(mst_arr > 0)
    for i, j in edge_coords:
        n1, n2 = node_list[i], node_list[j]
        adj_table[n1].append(n2)
        adj_table[n2].append(n1)
    
    # 统计节点度,识别叶子节点、分叉节点
    node_degree = {node: len(neighbors) for node, neighbors in adj_table.items()}
    leaf_nodes = [node for node, deg in node_degree.items() if deg == 1]
    junction_nodes = {node for node, deg in node_degree.items() if deg > 2}

    visited_edges = set()
    raw_tracks = []

    # 从每个叶子节点出发遍历提取轨迹段
    for leaf in leaf_nodes:
        current_path = [leaf]
        cur_node = leaf
        pre_node = None
        while True:
            # 排除上一个节点,找下一个可走的相邻节点
            next_candidates = [n for n in adj_table[cur_node] if n != pre_node]
            if not next_candidates:
                break
            next_node = next_candidates[0]
            # 用不可变集合标记无向边,避免重复遍历
            cur_edge = frozenset((cur_node, next_node))
            if cur_edge in visited_edges:
                break
            visited_edges.add(cur_edge)
            current_path.append(next_node)
            # 遇到分叉点或其他叶子节点则终止当前轨迹
            if next_node in junction_nodes or node_degree[next_node] == 1:
                break
            pre_node = cur_node
            cur_node = next_node
        # 过滤长度不足2的无效路径
        if len(current_path) >= 2:
            raw_tracks.append(current_path)
    
    # 处理无分叉的单链MST场景
    if not junction_nodes and len(raw_tracks) == 2:
        full_track = raw_tracks[0] + raw_tracks[1][::-1][1:]
        return [full_track]
    
    return raw_tracks

示例运行效果

使用题目给出的测试数据运行:

# 加载示例坐标数据
df = pd.DataFrame(
    [[2, 2], [30, 2], [2, 30], [25, 25], [14,10]],
    columns=['xcord', 'ycord'],
    index=['source', 'dest1', 'dest2', 'dest3', 'dest4']
)
# 提取主轨迹
track_result = extract_main_tracks(df)
print(track_result)

基础拆分输出为:

[['source', 'dest4'], ['dest1', 'dest4'], ['dest2', 'dest4'], ['dest3', 'dest4']]

如果需要得到示例中跨中心节点的长轨迹(如['dest2', 'dest4', 'dest1']、['source', 'dest4', 'dest3']),只需在分叉节点处按照业务规则(如边的方向、距离权重、轨迹走向)对拆分出的短轨迹做两两配对拼接即可,无需修改核心遍历逻辑。

该实现兼容任意坐标点输入,无需提前指定中心节点,自动适配多分叉、单链等不同结构的MST计算结果。

内容的提问来源于stack exchange,提问作者Ruthger Righart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 10:06:30