在每个分区中具有相等和的数组的N倍分区

时间:2013-05-07 09:03:34

标签: algorithm

给定一个整数数组a,两个数字NM,从N返回a个整数组,使每个组合计为{ {1}}。

例如,说:

  • M
  • a = [1,2,3,4,5]
  • N = 2

然后算法可以返回M = 5[2, 3], [1, 4]或可能返回其他人。

我可以在这里使用哪些算法?

编辑:

我不知道这个问题是NP完整的。因此,如果我提供有关我特定情况的更多详细信息,这可能会有所帮助:

所以我正在尝试创建一个“匹配”应用程序。考虑到团队数量[5], [2, 3]和每个团队的玩家数量N,应用程序会侦听客户端请求。每个客户端请求将给出客户端代表的许多玩家。因此,如果我需要2个5个玩家的团队,那么如果5个客户发送请求,每个请求分别代表1,2,3,4,5个玩家,那么我的应用程序应该在客户M和客户{之间产生匹配{1}}。它还可以生成[1, 4][2, 3]之间的匹配;我真的不在乎。

一个含义是代表[1, 4]或少于[5]个玩家的任何客户都无效。希望这可以简化问题。

3 个答案:

答案 0 :(得分:2)

这似乎是subset sum problem的变体。因为这个问题是np-complete,没有进一步的约束就没有有效的算法。

请注意,很难找到原始集合的单个子集,其元素总和为M

答案 1 :(得分:2)

人们很容易放弃NP完全问题。仅仅因为问题是NP完成并不意味着在一般情况下没有更多和更低效的算法。也就是说,你不能保证对于所有输入都有一个可以比强力搜索更快地计算的答案,但是对于许多问题,你当然可以拥有比大多数输入的完全搜索更快的方法。

对于这个问题,肯定有“反常”的数字集会导致最坏情况下的搜索时间,因为可能会说一个大的整数向量,但只有一个解决方案,你必须最终尝试一个非常大的数字组合。

但是对于非反常集合,可能存在许多解决方案,并且“跳过”良好分区的有效方式将比NP时间快得多。

你如何解决这个问题将取决于你期望的更常见的参数。如果整数都是正数,或者如果允许负数,它也会有所不同。

在这种情况下,我会假设:

  1. N相对于矢量的长度
  2. 所有整数都是正数。
  3. 无法重复使用整数。
  4. 算法:

    1. 对矢量进行排序,v。
    2. 消除大于M的元素。它们不能成为任何解决方案的一部分。
    3. 将所有剩余数字加到v中,除以N.如果结果小于M,则没有解决方案。
    4. 创建一个新的数组w,大小与v相同。对于每个w [i],求和v [i + 1 - end]中的所有数字
    5. 因此,如果v为5 4 3 2 1,w将为10,6,3,1,0。

      虽然你找不到足够的套装:

      1. 选择最大数字x,如果它等于M,则发出一个只有x的解集,并将其从向量中移除,从w中删除第一个元素。
      2. 仍然不够套? (可能),然后再次找不到足够的套装:

        1. 解理论是([a,b,c],R)其中[a,b,c]是v和余数R的元素的部分集合.R = M-sum [a,b,c] ]。扩展理论是在部分集合中添加一个数字,并从R中减去该数字。在扩展理论时,如果R == 0,那么这是一种可能的解决方案。
        2. 递归地创建这样的理论:循环遍历元素v,作为v [i]创建理论,([v [i]],R),现在递归地扩展将每个理论从v。二元搜索的一部分扩展到v找到等于或小于R的第一个元素v [j]。从v [j]开始并用v的元素从j扩展每个理论直到R> W [K]。

          从v [j]到v [k]的数字是用于扩展理论但仍然将R设为0的唯一数字。大于v [j]的数字将使R为负。小于v [k],并且数组中没有任何更多的数字,即使你使用它们全部得到R为0

答案 2 :(得分:0)

这是我自己的Python解决方案,它使用动态编程。该算法给出here

def get_subset(lst, s):
    '''Given a list of integer `lst` and an integer s, returns
    a subset of lst that sums to s, as well as lst minus that subset
    '''
    q = {}
    for i in range(len(lst)):
        for j in range(1, s+1):
            if lst[i] == j:
                q[(i, j)] = (True, [j])
            elif i >= 1 and q[(i-1, j)][0]:
                q[(i, j)] = (True, q[(i-1, j)][1])
            elif i >= 1 and j >= lst[i] and q[(i-1, j-lst[i])][0]:
                q[(i, j)] = (True, q[(i-1, j-lst[i])][1] + [lst[i]])
            else:
                q[(i, j)] = (False, [])

        if q[(i, s)][0]:
            for k in q[(i, s)][1]:
                lst.remove(k)

            return q[(i, s)][1], lst

    return None, lst

def get_n_subset(n, lst, s):
    ''' Returns n subsets of lst, each of which sums to s'''
    solutions = []
    for i in range(n):
        sol, lst = get_subset(lst, s)
        solutions.append(sol)

    return solutions, lst


# print(get_n_subset(7, [1, 2, 3, 4, 5, 7, 8, 4, 1, 2, 3, 1, 1, 1, 2], 5))
# [stdout]: ([[2, 3], [1, 4], [5], [4, 1], [2, 3], [1, 1, 1, 2], None], [7, 8])