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

基于代价矩阵的n元素k分组最大M值求解技术问询

这是一个典型的最大化最小阈值问题,非常适合用「二分查找 + 连通分量分析」来解决,我来帮你理清思路并给出完整解法:

问题重述

给定包含n个元素的代价矩阵cost,其中cost[i][j]表示元素i与j的代价。需要将n个元素划分为k个非空组,同组内元素对的代价视为0;设M为所有不同组元素对中的最小代价,我们要找到M的最大可能值。

你的思路修正与核心逻辑

你提到的「二分查找候选M」方向完全正确,但分组逻辑可以优化,避免“不确定是否合并组”的困惑:

原思路:将所有cost[i][j]排序后二分查找,假设当前M为候选值,要求代价为M的边(i,j)两端元素分属不同组;从i出发BFS,将所有相邻代价小于M的元素归为一组,再从j出发BFS处理下一组,遇到已分组且与当前组元素代价小于M的情况时,不确定是否需合并组。

我们可以换个角度思考:要让M成为跨组元素对的最小代价,本质是要求所有跨组元素对的代价≥M(这样M才是符合条件的候选值)。反过来推导:如果两个元素的代价<M,它们必须被分到同一组——否则这对元素的跨组代价<M,会直接导致M不符合要求。

基于这个逻辑,我们可以用**并查集(Union-Find)**高效验证候选M的可行性:

  • 对于候选M,把所有代价<M的元素对合并为同一组(因为它们不能跨组);
  • 统计合并后的连通分量数量m:
    • 如果m≥k:说明我们可以把这m个连通分量合并成k个组(比如将m-k+1个连通分量合并为一个组),且合并后所有跨组元素对的代价都≥M(不同连通分量之间的元素对代价必然≥M,否则会被合并),因此M可行;
    • 如果m<k:说明无法分成k个非空组(拆分连通分量会导致跨组代价<M),M不可行。
实例验证

用你给出的例子:n=3,k=2,代价矩阵为:

  • cost[1][2] = 17
  • cost[2][3] = 15
  • cost[1][3] = 16
  1. 候选代价排序后为[15,16,17]
  2. 验证M=16:
    • 合并所有代价<16的元素对(仅2和3),得到连通分量{1}, {2,3},数量m=2≥k=2,可行;
  3. 验证M=17:
    • 合并所有代价<17的元素对(2和3、1和3),得到连通分量{1,2,3},数量m=1<k=2,不可行;
  4. 最终最大可行M为16,与预期一致。
完整解法代码(伪代码)
def find_max_M(n, k, cost):
    # 收集所有不重复的代价并排序
    values = set()
    for i in range(n):
        for j in range(i+1, n):
            values.add(cost[i][j])
    values = sorted(values)
    if not values:
        return 0  # 特殊情况:n=1,此时k只能为1,无跨组元素对
    
    # 并查集实现
    def init_parent():
        return list(range(n))
    
    def find(u, parent):
        while parent[u] != u:
            parent[u] = parent[parent[u]]  # 路径压缩
            u = parent[u]
        return u
    
    def union(u, v, parent):
        u_root = find(u, parent)
        v_root = find(v, parent)
        if u_root != v_root:
            parent[v_root] = u_root
    
    max_M = values[0]
    left, right = 0, len(values)-1
    while left <= right:
        mid = (left + right) // 2
        current_M = values[mid]
        parent = init_parent()
        
        # 合并所有代价<M的元素对
        for i in range(n):
            for j in range(i+1, n):
                if cost[i][j] < current_M:
                    union(i, j, parent)
        
        # 统计连通分量数量
        roots = set()
        for u in range(n):
            roots.add(find(u, parent))
        m = len(roots)
        
        if m >= k:
            # 当前M可行,尝试更大的值
            max_M = current_M
            left = mid + 1
        else:
            # 当前M不可行,尝试更小的值
            right = mid - 1
    
    return max_M

调用示例:

n = 3
k = 2
cost = [
    [0, 17, 16],
    [17, 0, 15],
    [16, 15, 0]
]
print(find_max_M(n, k, cost))  # 输出:16

内容的提问来源于stack exchange,提问作者joan arc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:57:29