当前位置: 首页 > 知识库问答 >
问题:

将大小为N的集合拆分为M个组,这些组的和之间的差值最小

申浩广
2023-03-14

有一组大小N

S = {n1, n2, n3, ..., nN}

我需要在M上拆分集合S

Groups = {{n1, n2}, {n3, n4, n5...},...,{... nN}} -> len(Groups) = M

两个相邻组之间的最大差值应尽可能小。差额的计算方法如下:

diff = abs(sum(G1) - sum(G2)) = abs((n1 + n2) - (n3 + n4 + n5))

我可以生成所有大小为N的向量,其中只包含M非零位数(如1),但我将不得不考虑50! / (25! * 25!)为错误的蛮力:(

例子:

6, 13, 10, 2
case 1: {6}, {13, 10, 2} -> difference = 25
case 2: {6, 13}, {10, 2} -> difference = 5
case 3: {6, 13, 10}, {2} -> difference = 29
The best case is second -> difference = 5!

我可以用什么方法来解决这个问题?


共有1个答案

罗鸿福
2023-03-14

我通过结合动态规划和修改a*搜索解决了这个问题。

import heapq

def best_division (numbers, pieces):
    cumulative_sums = [0]
    for number in numbers:
        cumulative_sums.append(cumulative_sums[-1] + number)

    # We need this to be somewhat bigger than the maximum sum.
    # Making it + pieces/2 will result in a better
    # expected_piece_size.
    sum_bound = cumulative_sums[-1] + (pieces // 2)

    # We expect our pieces to be somewhere close to this size.
    expected_piece_size = (cumulative_sums[-1] + (pieces//2)) // pieces

    # This data structure will include:
    #
    #   By completed segments
    #       By start of segment
    #           By end of segment
    #               (lowest maximum difference, prev_start)
    #
    # It will actually be an array of dictionaries of dictionaries.
    #
    # It starts off empty.
    best_path_info = []

    # The queue is a minimum priority queue.
    #
    #   [
    #       lowest maximum difference,
    #       abs(sum of segment - expected_piece_size),
    #       count_pieces,
    #       start,
    #       end,
    #       prev_start
    #   ]
    #
    # This causes us to first look at the lowest maximum difference,
    # and then at the segment sum being close to the expected.
    #
    # It also means we can trace backwards once we have an answer.
    queue = []

    for i in range(len(cumulative_sums)):
        heapq.heappush(
            queue, [
                0,
                abs(cumulative_sums[i] - expected_piece_size),
                0,
                0,
                i,
                None
            ])

    while len(queue):
        max_diff, _, count_completed, start, end, prev_start = heapq.heappop(queue)
        if count_completed + 1 == pieces: # The current piece is not in the count
            if end == len(numbers):
                answer = [numbers[start:end]]
                end = start
                start = prev_start
                while start is not None:
                    answer.append(numbers[start:end])
                    count_completed -= 1
                    prev_start = best_path_info[count_completed][start][end][1]
                    end = start
                    start = prev_start
                ### RETURN HERE ###
                return list(reversed(answer))

            else:
                continue # Not a solution

        if len(best_path_info) <= count_completed:
            best_path_info.append({})

        path = best_path_info[count_completed]
        if start not in path:
            path[start] = {}
        path = path[start]
        if end not in path or max_diff < path[end][0]:
            path[end] = (max_diff, prev_start)
            for next_end in range(end, len(cumulative_sums)):
                this_sum = cumulative_sums[end] - cumulative_sums[start]
                next_sum = cumulative_sums[next_end] - cumulative_sums[end]
                next_max_diff = max(max_diff, abs(next_sum - this_sum))
                heapq.heappush(
                    queue, [
                        next_max_diff,
                        abs(next_sum - expected_piece_size),
                        count_completed + 1,
                        end,
                        next_end,
                        start
                    ])
 类似资料:
  • 如何将整数数组划分为N个子集,使这些子集的和最小? 例如,数组由11个元素组成,我需要其中的6个子集。 子集:<code>{2,1,1,3},{4},}4,3},}3,2},1,2},{3}</code>最小和=7。 另一个答案是:最小和=7。 注意:在分区时,必须保持数字在原始集合中出现的顺序。

  • 我正在尝试解决此问题: 一位物理教授给班上的学生做项目。学生们必须组成一个两人小组来做这个项目。教授让学生来决定队伍。一个班级的学生人数将是偶数。 每个学生都有自己的知识水平。它告诉每个学生有多少知识。一个团队的知识水平是两个学生知识水平的总和。 学生们决定组成小组,这样知识最高的团队和知识最低的团队之间的差异就最小了。 投入 输入的第一行将包含测试用例的数量t;在接下来的t行中,第一个数字是n,

  • 问题内容: 想象一下,我有一个这样的JS数组: 我想要的是将该数组拆分为N个较小的数组。例如: 对于Python,我有这个: 对于JS,我可以提出的最佳解决方案是递归函数,但我不喜欢它,因为它既复杂又丑陋。这个内部函数返回一个像这样的数组[1,2,3,null,4,5,6,null,7,8],然后我必须再次循环并手动拆分它。(我的第一次尝试是返回此:[1、2、3,[4、5、6,[7、8、9]]],

  • 我想从数组的一部分找到最大值和最小值。我知道我可以通过复制数组将所需的数组部分复制到另一个数组中,但只是想知道是否可以不复制数组,因为我必须为不同的子数组进行循环 例如: 现在我想从1到4找到子数组的最小/最大值(如果可能,不复制子数组)

  • 基本上,我要问的是给定一个正方形2D阵列和一个有效的补丁大小(2D子阵列的大小),我将如何做到这一点。最终,我不需要以任何方式存储子阵列,我只需要找到每个子阵列的中值并将它们存储在一个一维阵列中。中值和存储到新阵列对我来说很简单,我只是不知道如何处理原始2D阵列并正确拆分它。我已经尝试了几次,但一直出现越界错误。我有一个4x4: 我需要像这样拆分它 < code>[1,2] [3,4] [2,3]

  • 假设我有一个包含整数的数组。 如何找到大小的子集,使得子集中所有整数对之间的距离,我的意思是它们在最远的距离。 示例:数组和, ,最小距离为10和6之间的<错误的子集: ,最小距离为 ,最小距离为 我想到了一个解决办法: 1) 排序数组2)选择一个[0],现在在数组中查找ceil(a[0])=Y。。。。然后ceil(Y