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

如何优化三分组最小化最大和的O(3^n)复杂度算法

三分组最小最大和算法优化方案

问题回顾

需将正整数数组划分为3个分组,最小化三组的最大和值。原算法采用暴力回溯,时间复杂度O(3^n),远慢于作业要求的O(l²n³),需针对性优化。


核心优化思路

1. 预排序剪枝

先将数组降序排序,优先处理大元素。大元素对分组容量的限制更严格,能快速排除不可能的分支,大幅减少无效递归/计算。

2. 记忆化搜索+状态去重

原递归的状态(n, a, b, c)存在大量重复(分组无序,(a,b,c)与(b,a,c)等价),通过以下方式优化:

  • 对剩余容量排序,将状态简化为(idx, rem1, rem2, rem3)(rem1≥rem2≥rem3),减少重复状态数。
  • 用记忆化缓存已计算的状态,避免重复计算。

3. 动态规划(DP)实现

采用DP替代递归回溯,严格满足时间复杂度要求。定义状态dp[s1][s2]表示是否能选出两个子集和为s1和s2(均≤目标值target),且剩余元素和total-s1-s2 ≤ target。


优化后代码实现

方案一:记忆化回溯(适合中等规模数组)

import functools

def works(array, target):
    # 降序排序,优先处理大元素
    sorted_arr = sorted(array, reverse=True)
    n = len(sorted_arr)

    @functools.lru_cache(maxsize=None)
    def backtrack(idx, rem1, rem2, rem3):
        if idx == n:
            return True
        num = sorted_arr[idx]
        # 剪枝:当前元素大于所有剩余容量,直接返回False
        if num > rem1 and num > rem2 and num > rem3:
            return False
        
        # 尝试放入第一个组,排序剩余容量去重
        if rem1 >= num:
            new_rem = sorted([rem1 - num, rem2, rem3], reverse=True)
            if backtrack(idx + 1, *new_rem):
                return True
        # 仅当剩余容量不同时尝试放入第二个组,避免重复状态
        if rem2 >= num and rem2 != rem1:
            new_rem = sorted([rem1, rem2 - num, rem3], reverse=True)
            if backtrack(idx + 1, *new_rem):
                return True
        # 仅当剩余容量不同时尝试放入第三个组
        if rem3 >= num and rem3 != rem2 and rem3 != rem1:
            new_rem = sorted([rem1, rem2, rem3 - num], reverse=True)
            if backtrack(idx + 1, *new_rem):
                return True
        return False

    return backtrack(0, target, target, target)

def minimum_allowable_attendance_for_long_weekend(input_file_path, output_file_path):
    import math
    # 读取输入文件(假设元素以空格/换行分隔)
    with open(input_file_path, 'r') as f:
        array = list(map(int, f.read().split()))
    total = sum(array)
    max_num = max(array)
    # 初始目标值:取数组最大值和总和1/3的上界中的较大者
    start_target = max(max_num, math.ceil(total / 3))
    answer = total  # 最坏情况:所有元素在一个组

    for target in range(start_target, total + 1):
        if works(array, target):
            answer = target
            break
    
    # 写入结果到输出文件
    with open(output_file_path, 'w') as f:
        f.write(str(answer))

方案二:动态规划(满足O(l²n³)时间复杂度要求)

def works_dp(array, target):
    total = sum(array)
    # 初始化DP表:prev_dp[s1][s2]表示能否得到两个子集和为s1、s2
    prev_dp = [[False] * (target + 1) for _ in range(target + 1)]
    prev_dp[0][0] = True

    for num in array:
        # 复制上一轮状态,对应"不放入任何子集"的选择
        curr_dp = [row.copy() for row in prev_dp]
        for s1 in range(target + 1):
            for s2 in range(target + 1):
                if prev_dp[s1][s2]:
                    # 放入第一个子集
                    if s1 + num <= target:
                        curr_dp[s1 + num][s2] = True
                    # 放入第二个子集
                    if s2 + num <= target:
                        curr_dp[s1][s2 + num] = True
        prev_dp = curr_dp
    
    # 检查是否存在符合条件的子集组合
    for s1 in range(target + 1):
        for s2 in range(target + 1):
            if prev_dp[s1][s2] and (total - s1 - s2) <= target:
                return True
    return False

def minimum_allowable_attendance_for_long_weekend(input_file_path, output_file_path):
    import math
    with open(input_file_path, 'r') as f:
        array = list(map(int, f.read().split()))
    total = sum(array)
    max_num = max(array)
    start_target = max(max_num, math.ceil(total / 3))
    answer = total

    for target in range(start_target, total + 1):
        if works_dp(array, target):
            answer = target
            break
    
    with open(output_file_path, 'w') as f:
        f.write(str(answer))

复杂度分析

  • 记忆化回溯:时间复杂度约为O(n*target²),状态数被排序去重后大幅减少,实际运行效率远高于原O(3^n)算法。
  • 动态规划:时间复杂度为O(ntarget²),其中target的数量级为O(nmax_element),代入后得到O(n³*max_element²),完全符合作业要求的O(l²n³)(l为数组元素最大值)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 22:20:34