V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
tanszhe
V2EX  ›  程序员

这个算法有多难? 把 Ai 也难到了

  •  
  •   tanszhe · 21 小时 50 分钟前 · 1700 次点击

    坐标系中有一些点 points(x,y),请写一个算法来给这些点分组。

    要求:

    1. 同一组内的点,它们之间的距离不能大于 d
    2. 分组数量要最少
    3. 每组的点数不能超过 m
    4. 设:每组内链接所有点最短的那条连线(最优路径)= l , 要求所有组的 l 加起来尽可能小 (有些点可以同时分在多个组时 需要考虑全局最优)

    d 和 m 可以自定义配置

    16 条回复    2025-02-22 12:51:49 +08:00
    liu731
        1
    liu731  
       21 小时 46 分钟前
    你这不物流排程系统吗?网上没有的 Ai 也太会啊。
    murmur
        2
    murmur  
       21 小时 45 分钟前
    这个东西如果是物流系统,算法是解决不了的,实际上还要考虑交通、租金、劳动力、消费能力

    比如广东深圳,挨得很近,也是双仓库
    tanszhe
        3
    tanszhe  
    OP
       21 小时 24 分钟前
    @murmur 不用考虑这些 不是物流
    qwertyzzz
        4
    qwertyzzz  
       21 小时 19 分钟前
    为啥我问 ai ai 给出答案了 有测试用例吗
    tanszhe
        5
    tanszhe  
    OP
       21 小时 11 分钟前
    @qwertyzzz 你随便列 20 个点 比如 d=6 ,m =5 可以看看 ai 都是错误的
    ccpp132
        6
    ccpp132  
       21 小时 9 分钟前   ❤️ 2
    光你第四点,就是个最短哈密尔顿路径,目前没有多项式的算法
    tanszhe
        7
    tanszhe  
    OP
       20 小时 32 分钟前
    @ccpp132 穷举呢?
    ccpp132
        8
    ccpp132  
       20 小时 2 分钟前
    @tanszhe 那就穷举呗
    openmynet
        9
    openmynet  
       19 小时 54 分钟前
    你这应该找的是聚类这方面的算法,比如 dbscan 之类的,好一点的可以试试基于 infomap 的聚类,或者 louvain 、Leiden
    kaishi123
        10
    kaishi123  
       19 小时 34 分钟前
    看不懂,但是问了下马首富,马首富思考了 17 秒就给出了答案。太长了就不复制了。


    ### 算法思路

    1. **计算距离矩阵**:首先计算所有点之间的距离,以便快速判断点对是否满足距离约束 `d`。
    2. **初始聚类**:使用 DBSCAN 聚类算法初步分组,设置距离阈值 `d`,确保组内点之间的距离不超过 `d`。
    3. **分割大聚类**:检查每个聚类的大小,如果超过 `m`,则将其分割成多个大小不超过 `m` 的子聚类。
    4. **优化路径**:对每个聚类计算其内部最优路径长度 `l`(使用旅行商问题 TSP 的近似解法)。
    5. **重叠优化**:允许某些点在多个组中重叠,通过贪心策略调整分组,尝试最小化所有 `l` 的总和。
    6. **最小化分组数量**:在满足上述条件的基础上,合并较小的聚类以减少分组数量。
    chen1star
        11
    chen1star  
       18 小时 24 分钟前
    首先,问题要求将若干坐标点分组,给定的约束条件包括:组内两点的距离不超过 d ,且每组的点数不超过 m ,同时优化总路径长度。

    我需要先考虑如何计算组内的最短路径( l ),优化这个路径长度的同时满足每组条件。可能需要用到图算法来处理距离限制,同时还要优化分组的数量。关键是找到既能保持点的距离,又能最小化路径总和的方法。

    我应该从两点之间距离的计算入手。

    该问题涉及带约束的聚类,要求每组内两点之间的最大距离不超过 d ,同时最小化每组的路径长度。每组的点数不能超过 m ,而且某些点可以属于多个组。优化目标是最小化所有组路径长度的总和。考虑到问题是 NP 难度,我可能需要使用贪心算法或迭代聚类的策略。一种可能的策略是通过分割点集来逐步逼近全局最优解。

    我可以通过以下步骤来设计算法:首先,计算点间的所有距离,构建图并检查每个组是否为完全连通。然后,可以使用贪心策略,将点分配到现有组中,满足距离和容量约束。如果无法分配,再创建新组。同时,尝试合并接近的组以最小化总数,并检查是否允许点 belonging to multiple groups 来减少 TSP 路程总和。我可能会使用递归分区或聚类方法来进一步优化。

    下面给出一种基于启发式搜索和局部优化的整体思路。注意:由于问题同时兼顾“组内所有点两两距离不超过 d”、“每组点数上限 m”、“组数最少”以及“各组最优路径(例如近似 TSP 路径)总长尽可能小”,而这几个目标之间可能会产生冲突,所以问题本质上属于 NP‐hard (甚至是多目标组合优化问题),因此下面的算法设计主要为启发式和近似方法,实际应用中可能需要根据问题规模做进一步调优。

    算法思路概述
    构造邻接图
    将所有点看作图中的节点,构造一个无向图
    𝐺
    =
    (
    𝑉
    ,
    𝐸
    )
    G=(V,E) ,其中对任意两个点
    𝑝
    𝑖
    ,
    𝑝
    𝑗
    p
    i

    ,p
    j

    ,如果它们之间的欧式距离不大于
    𝑑
    d ,则在图中建立一条边。这样,同一组内任意两点均应是图中的邻居。

    初步分组:生成可行覆盖
    基于上一步的图,可以考虑“团( clique )”或者“完全子图”来满足组内任意两点距离都不大于
    𝑑
    d 。但同时要求每组点数不超过
    𝑚
    m ,所以可以采用以下贪心策略:

    排序和选择:对所有点进行某种顺序排序(例如:按坐标、密度或度数排序);
    构造候选组:从未分配的点中取出一个点
    𝑝
    p ,将其作为组的种子,然后遍历与
    𝑝
    p 相邻(且与已选组内所有点均满足距离

    𝑑
    ≤d )的点,依次加入组中(直到不能再加或者已达到上限
    𝑚
    m );
    重复:更新未覆盖的点集,直至所有点至少被覆盖一次。
    此处允许“覆盖重叠”,即某些点可以出现在多个组中,以便后续在全局优化时获得更好的 TSP 路径总长。
    组内 TSP 路径评估
    对于每个候选组,采用近似 TSP 算法(如最近邻启发式、2-opt 或其他近似方法)计算“组内最短连通路径长度”
    𝑙
    l 。这一步用于衡量当前分组的“紧凑度”。

    目标是使得所有组的
    𝑙
    l 值之和尽可能小。
    局部搜索与迭代改进
    在初步分组的基础上,采用局部搜索策略改进整体方案。关键步骤包括:

    合并尝试:检查两个或多个相邻(或重叠)组,尝试合并成一个更大的组,前提是合并后所有点依然满足任意两点距离

    𝑑
    ≤d 且组内点数不超过
    𝑚
    m 。若合并后整体 TSP 路径的总长下降,同时组数减少,则接受该操作。
    边界调整:对于位于多个组交界处的点,尝试“复制”其到多个组中或调整所属关系,从而使得各组内部更紧凑,进而降低 TSP 路径长度。
    局部交换:考虑将某个组中的一个点移至另一个组(或者同时存在于两个组中),前提是移动后两个组都满足距离和容量限制,且整体目标(组数最少且 TSP 总长降低)得到改善。
    目标函数:整个局部搜索的目标可以设计为一个加权函数,例如
    𝐹
    =
    𝛼
    ×
    (
    组数
    )
    +
    𝛽
    ×
    (

    𝑖
    𝑙
    𝑖
    )
    F=α×(组数)+β×(
    i


    l
    i

    )
    其中
    𝛼
    ,
    𝛽
    α,β 为权重,反映“先求最少组数,再求紧凑”的要求。
    终止条件
    当连续多次局部搜索未能改进目标函数,或达到预设的迭代次数时,算法终止,输出当前的分组方案。

    伪代码示例
    python
    复制
    # 假设 points 是所有点的列表,每个点格式为 (x, y)

    def build_graph(points, d):
    G = {p: set() for p in points}
    for i in range(len(points)):
    for j in range(i+1, len(points)):
    if distance(points[i], points[j]) <= d:
    G[points[i]].add(points[j])
    G[points[j]].add(points[i])
    return G

    def initial_grouping(points, G, m):
    groups = []
    uncovered = set(points)
    # 可根据度数或密度对点排序,下面简单按列表顺序处理
    while uncovered:
    p = uncovered.pop()
    group = {p}
    # 遍历与 p 邻接且与当前组所有点距离 <= d 的点
    candidates = [q for q in G[p] if q in uncovered]
    for q in candidates:
    if len(group) >= m:
    break
    if all(distance(q, r) <= d for r in group):
    group.add(q)
    uncovered.discard(q)
    groups.append(group)
    return groups

    def compute_tsp_length(group):
    # 使用近似 TSP 算法计算该组点的最优路径长度
    # 这里可以用最近邻法或 2-opt 改进,返回近似值 l
    return approx_tsp_length(group)

    def local_search(groups, d, m, alpha, beta):
    improved = True
    while improved:
    improved = False
    # 尝试合并组、交换点等局部操作
    for g1, g2 in candidate_group_pairs(groups):
    if can_merge(g1, g2, d, m):
    new_group = g1.union(g2)
    old_cost = compute_tsp_length(g1) + compute_tsp_length(g2) + alpha*2
    new_cost = compute_tsp_length(new_group) + alpha*1
    if new_cost < old_cost:
    groups.remove(g1)
    groups.remove(g2)
    groups.append(new_group)
    improved = True
    break
    if improved:
    continue

    # 对边界点进行交换或复制操作
    for group in groups:
    for p in list(group):
    # 尝试将 p 也加入到相邻组中或从当前组移除
    for other in groups:
    if other is group:
    continue
    if p not in other and all(distance(p, q) <= d for q in other) and len(other) < m:
    # 评估 p 同时属于两个组对整体目标的影响
    cost_before = compute_tsp_length(group) + compute_tsp_length(other)
    # 这里假设允许 p 同时在两个组中
    new_cost = compute_tsp_length(group) + compute_tsp_length(other)
    if new_cost < cost_before:
    other.add(p)
    improved = True
    break
    if improved:
    break
    if improved:
    break
    return groups

    def overall_algorithm(points, d, m, alpha=1, beta=1):
    G = build_graph(points, d)
    groups = initial_grouping(points, G, m)
    # 计算初始目标函数值
    total_tsp = sum(compute_tsp_length(g) for g in groups)
    cost = alpha * len(groups) + beta * total_tsp

    # 迭代局部搜索改进分组方案
    groups = local_search(groups, d, m, alpha, beta)
    return groups
    说明与扩展
    图构造阶段保证了每组内任意两点间的距离均不超过
    𝑑
    d 。
    初步分组阶段采用贪心策略生成一组覆盖,同时尽可能让组内点紧密。
    TSP 路径近似:由于精确求解 TSP 是 NP-hard ,通常采用近似算法;这部分可以根据具体场景进行调节。
    局部搜索:采用合并、交换、边界复制等操作,以便在满足约束(距离、容量)的前提下,减少分组数量并降低整体路径长度。
    多目标优化:目标函数中加入了组数和各组路径长度的权重,允许调节“先组数最少”还是“路径更短”两个目标的优先级。
    允许重叠:在局部搜索中可以允许某些点出现在多个组中,这在一些边缘点附近可能有助于全局优化。
    总结
    整体算法利用“构图—初分组—TSP 评估—局部搜索改进”的框架,对满足“组内距离不超过 d”、“组内容量不超过 m”条件的分组进行优化。由于问题本质的 NP-hard 特性,实际求解时需要借助启发式和近似方法,并根据具体场景(点的数量、分布、参数 d 与 m )对算法细节做针对性调优。

    这种设计既考虑了最小化组数的需求,也通过局部改进降低了每组内连接路径的长度,从而在允许部分点重叠的条件下尽可能达到全局最优。 --------------chtgpt o3-mini-high 给出的答案,不知道对不对?
    djw123
        12
    djw123  
       18 小时 21 分钟前
    @chen1star 没看右边吗?
    • 请不要在回答技术问题时复制粘贴 AI 生成的内容
    iOCZS
        13
    iOCZS  
       15 小时 49 分钟前
    又有聚类,又有 np hard 的影子
    alluofuyo
        14
    alluofuyo  
       12 小时 22 分钟前
    粗略一看,数学建模,然后混合整数规划求解,用求解器算,自己写算法太费脑子
    xiaoming1992
        15
    xiaoming1992  
       3 小时 19 分钟前 via Android
    @chen1star #11 这种又臭又长连换行都不处理一下就闭着眼睛粘贴上来的,确实污染时间线。
    chen1star
        16
    chen1star  
       1 小时 5 分钟前
    @xiaoming1992 我也是看了标题,说是 AI 解决不了才进来看的,我只是验证了一下,想把 AI 的思考过程都贴出来,所以内容多了一点。初次发帖没注意到右边提醒,那是我的错。关于回车,目前没有提供富文本内容的格式吧,反正我是没有看到。如果觉得难看可以不看,不要浪费时间你时间!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2774 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 05:56 · PVG 13:56 · LAX 21:56 · JFK 00:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.