是否存在满足不等式的n/2个元素的子集之和?

2024-09-26 22:52:17 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑到这些测试用例:

votes = [6]*28
m = 10

votes1 = [5]*28+[6]*2
m1 = 10

votes2 = [5]*29+[10]*1
m2 = 10

votes3 =  [8, 8, 16, 12, 12, 12, 4, 4, 12, 4, 4, 4, 8, 12, 12, 8, 8, 16, 12, 4, 16, 16, 12, 16, 12, 16, 12, 4, 16, 4, 4, 12, 4, 12, 12, 4, 16, 12, 16, 8]
m3 =  20

votes4 =  [22, 21, 34, 39, 28, 33, 32, 40, 22, 34, 36, 27, 37, 34, 40, 38, 39, 32, 37, 40, 31, 37, 22, 21, 35, 34, 24, 40, 34, 21, 24, 20, 30, 31, 22, 30, 31, 25, 20, 38, 24, 23, 32, 27, 20, 31, 27, 32, 22, 32, 33, 34, 40, 38, 36, 29, 34, 24, 24, 39, 32, 37, 30, 20, 29, 26, 36, 40, 34, 22, 30, 27, 38, 27, 26, 28, 23, 40, 31, 22, 23, 35, 23, 31, 23, 39, 30, 20, 20, 35, 27, 23, 23, 29, 40, 20, 34, 40, 28, 25]
m4 =  50

votes5 =  [25, 25, 25, 24, 25, 24, 24, 25, 26, 25, 26, 24, 25, 26, 24, 26, 24, 26, 26, 25, 26, 24, 26, 24, 26, 26, 26, 25, 25, 26, 24, 26, 25, 25, 24, 25, 25, 26, 26, 26, 25, 26, 25, 26, 25, 25, 24, 24, 24, 25, 24, 26, 25, 24, 26, 24, 24, 26, 24, 26, 24, 24, 24, 26, 24, 25, 24, 26, 25, 25, 26, 25, 25, 25, 25, 26, 25, 24, 25, 25, 24, 24, 24, 26, 26, 26, 25, 24, 25, 25, 25, 26, 25, 24, 26, 24, 25, 26, 24, 26]
m5 =  50

给定以下界限:

^{pr2}$

我想找出是否有一个长度正好为len(votes)/2的子集之和,它满足给定的upperbound和{}。在

下面是我用背包解决问题的尝试,但它没有考虑子集的长度。在

import math


def winnable(votes, m):
    n = len(votes)  # Number of columns
    v = sum(votes)
    ub = upperbound(v, m, n)
    lb = lowerbound(m, n)

    max_possible = knapSack(ub, votes, n)

    if max_possible < lb:
        return "not possible"
    else:
        return "possible"


def knapSack(ub, val, n):
    K = [[0 for x in range(ub + 1)] for x in range(n + 1)]

    # Build table K[][] in bottom up manner
    for i in range(n + 1):
        for w in range(ub + 1):
            if i == 0 or w == 0:
                K[i][w] = 0
            elif val[i - 1] <= w:
                K[i][w] = max(val[i - 1] + K[i - 1][w - val[i - 1]], K[i - 1][w])
            else:
                K[i][w] = K[i - 1][w]

    return K[n][ub]

是否可以进一步修改我的解决方案以考虑子集中元素的数量。在


Tags: inforlenreturndefrangevalmax
2条回答

我已经实现了@mrmcgreg向问题添加额外维度的建议

import math

def has_valid_subset(votes, m):
    n = len(votes)
    sum_min = math.ceil(0.25 * m * n + 1)
    sum_max = math.floor(sum(votes) - 0.25 * m * n - 1)
    n_half = n // 2
    K = [[[(False, 0) for elements in range(min(n_half + 1, index + 1))]
          for index  in range(len(votes) + 1)]
         for weight in range(sum_max + 1)]
    for weight in range(sum_max + 1):
        for index in range(len(votes) + 1):
            if index == 0:
                K[weight][index][0] = (True, 0)
                continue
            v = votes[index - 1]
            for elements in range(min(n_half + 1, index)):
                if v > weight:
                    K[weight][index][elements] = K[weight][index - 1][elements]
                else:
                    skip_ok, skip_w = K[weight][index - 1][elements]
                    add_ok, add_prev_w = K[weight - v][index - 1][elements - 1]
                    add_w = add_prev_w + v
                    if skip_ok and add_ok:
                        K[weight][index][elements] = (True, max(skip_w, add_w))
                    elif skip_ok:
                        K[weight][index][elements] = (True, skip_w)
                    elif add_ok:
                        K[weight][index][elements] = (True, add_w)
    b_max, w_max = K[-1][-1][-1]
    if not b_max:
        return False
    return w_max >= sum_min

测试:

^{pr2}$

这是一个合理有效的解决方案的核心。轻微测试,但可能是正确的。(最大的问题是,您希望解决方案包括边界还是排除它们?)在

def subset_sum_of_len_in_range (vals, total_to_use, lower, upper):
    # Sorting it makes it easy to calculate min/max of partial sum
    # from here - it will be the beginning or end.  This will be
    # useful in filtering.
    sorted_vals = sorted(vals)

    # Precalculating partial sums from beginning makes partial sum
    # of a range even easier - just subtract two.
    total = 0
    cum_prev_sum = [total]
    for i in sorted_vals:
        total = total + i
        cum_prev_sum.append(total)

    # It is always easiest to solve DP problems by caching recursive ones.
    cache = {}

    # And now our recursive cached solver.
    def sub_problem (position, to_use, current_sum):
        if len(vals) - position < to_use:
            # Not enough values left to possibly solve this.
            return False

        cache_key = (position, to_use, current_sum)
        if cache_key not in cache:
            lowest_sum = current_sum + cum_prev_sum[position + to_use] - cum_prev_sum[position]
            if upper < lowest_sum:
                # Can't possibly get in range.
                cache[cache_key] = False
                return False
            elif lower <= lowest_sum:
                # Found one in range!
                cache[cache_key] = True
                return True

            highest_sum = current_sum + cum_prev_sum[len(vals)] - cum_prev_sum[len(vals) - to_use]
            if highest_sum < lower:
                # Can't possibly get in range.
                cache[cache_key] = False
                return False
            elif highest_sum <= upper:
                # Found one in range!
                cache[cache_key] = True
                return True

            # Now try recursion.
            if sub_problem(position + 1, to_use, current_sum):
                # There is a solution that did not use this value
                cache[cache_key] = True
            elif sub_problem(position + 1, to_use-1, current_sum + vals[position]):
                # There is a solution that did use this value
                cache[cache_key] = True
            else:
                # There is no solution.
                cache[cache_key] = False


        return cache[cache_key]

    return sub_problem(0, total_to_use, 0)

用它来解决你的问题。。。在

^{pr2}$

相关问题 更多 >

    热门问题