如何检查数组中是否有总和?

时间:2019-03-16 07:03:37

标签: python algorithm

  

给出一个由 N 个整数组成的数组,通过选择数组中的一些(或不添加)元素来检查是否有可能获得 S 的和。 。

我尝试使用贪婪方法解决此问题,方法是先对数组进行排序,然后越来越接近总和。但是它不起作用。

谁能告诉我该如何解决这个问题?

t = int(input())
for foo in range(t):
    n = int(input())
    arr = list(map(int, input().split()))
    s = int(input())
    sum = 0

    for a in range(len(arr)):
        for b in range(len(arr)-a-1):
            if(arr[b] > arr[b+1]):
                temp = arr[b]
                arr[b] = arr[b+1]
                arr[b+1] = temp

    for i in arr:
        if((sum + i) <= s):
            sum += i

    if(sum == s):
        print("YES")
    else:
        print("NO")

3 个答案:

答案 0 :(得分:3)

使用itertools.combinations的强力解决方案(可能非常缓慢):

from itertools import combinations

def is_possible_sum(numbers, n):
    # One of those rare cases where range() is ok!
    for r in range(len(numbers)):
        for combo in combinations(numbers, r + 1):
            if sum(combo) == n:
                return True
    return False

答案 1 :(得分:1)

动态和组合解决方案以及时间/结果测试代码:

# The subset sum problem:
#
# Given an array of N integers, check if it is possible to obtain a sum of S,
# by choosing some (or none) elements of the array and adding them.
#
# The code contributors are Alexander Lopatin, Sahil Shelangia, DYZ


def if_possible_sum_obvious(a, s):
    if a is None or len(a) == 0:
        return s == 0
    if s > 0:
        if s > sum([i for i in a if i > 0]):
            return False
    elif s < 0:
        if s < sum([i for i in a if i < 0]):
            return False
    else:
        for i in a:
            if i == 0:
                return True
        else:
            return False
    return None


def is_possible_sum_dynamic(a, s):  # Dynamic Programming
    if a is None or len(a) == 0:
        return s == 0
    n = len(a)
    b = [[False for _ in range(s + 1)] for _ in range(n + 1)]
    for i in range(n + 1):
        b[i][0] = True
    for i in range(1, s + 1):
        b[0][i] = False
    for i in range(1, n + 1):
        for j in range(1, s + 1):
            if j < a[i - 1]:
                b[i][j] = b[i - 1][j]
            if j >= a[i - 1]:
                b[i][j] = (b[i - 1][j] or b[i - 1][j - a[i - 1]])
    return b[n][s]


def is_possible_sum_combinations(a, s):  # combinations from itertools
    check_obvious = if_possible_sum_obvious(a, s)
    if check_obvious is not None:
        return check_obvious
    from itertools import combinations
    for r in range(len(a)):
        for combo in combinations(a, r + 1):
            if sum(combo) == s:
                return True
    return False


if __name__ == '__main__':
    import time
    for f in [is_possible_sum_dynamic, is_possible_sum_combinations]:
        print('\nTesting function:', f.__name__)
        for N in range(40):
            a_global = [i+1 for i in range(N)]
            sum2check = sum(a_global)
            print(N, end='')

            def time_and_check(f_local, sum_local, expected):
                t0 = time.perf_counter_ns()
                possible = f_local(a_global, sum_local)
                t1 = time.perf_counter_ns() - t0
                print('', t1, sep=',', end='' if expected else '\n')
                if possible != expected:
                    print('Not possible! Strange')
                    print(sum_local, a_global, sep='\n')
                    exit(1)

            time_and_check(f, sum2check, True)
            time_and_check(f, sum2check + 1, False)

我添加了动态编程解决方案,并修改了DYZ的代码,以避免通过if_possible_sum_obvious(a,s)调用而明显陷入困境。可以添加相同的函数,而不是is_possible_sum_dynamic函数中的前两行,但随后我必须再次运行此长时间测试并重新制作图形。 Axis X is N integers, Y - log10(time in nanoseconds): 1 = 1 ns, 9 = 1 sec, 12 = 1000 sec X轴是整数,Y轴-log10(以纳秒为单位的时间):3 = 10 ** 3 ns = 1μs,9 = 1 sec,12 = 1000 sec

输出:

Testing function: is_possible_sum_dynamic
0,2630,740
1,7068,5588
2,8120,8725
3,13344,14298
4,22849,24119
5,36515,57237
6,70649,59626
7,83752,86483
8,119746,123067
9,162509,167441
10,217729,263601
11,285210,289287
12,405059,368185
13,461434,462611
14,568958,569770
15,687595,1110547
16,957992,869849
17,998072,1074423
18,1381996,1460914
19,1455941,1399456
20,1803727,1608306
21,1968317,2000050
22,2482750,2602217
23,2737389,2424789
24,2756149,2802634
25,3581139,3282499
26,3360480,3421020
27,3778212,4037443
28,4295289,4182019
29,4850601,4657451
30,5294141,5060018
31,5955458,5811096
32,6386726,6341719
33,6848117,6843303
34,7589508,7485276
35,8231171,8118034
36,8921163,9172343
37,10649931,11339668
38,11922632,11463180
39,12720235,12802786

Testing function: is_possible_sum_combinations
0,3535,880
1,170306,2222
2,5823,1460
3,5944,1441
4,7736,1411
5,11908,1522
6,18459,1565
7,32447,1630
8,59748,1812
9,118461,2062
10,237636,3110
11,495370,3816
12,1007225,4040
13,1945018,3824
14,4091327,6125
15,9028434,6253
16,16549245,5440
17,35843517,5611
18,64125274,5158
19,137040747,5894
20,284994834,6748
21,538974234,5722
22,1108166024,5654
23,2242642192,6019
24,4642429033,6166
25,9368977496,6358
26,18792906166,6285
27,38892974776,6442
28,78689360778,6324
29,160660909206,7009
30,330681016443,7278
31  ,684805660485,10669
32,1361937299206,7018
33

答案 2 :(得分:0)

您检查此代码

# sum using elements of the given array. 
def check(arr, N): 

    ispossible[0] = 1
    arr.sort() 

    for i in range(0, N): 
        val = arr[i] 

        # if it is already possible 
        if ispossible[val]: 
            continue

        # make 1 to all it's next elements 
        for j in range(0, MAX - val): 
            if ispossible[j]: 
                ispossible[j + val] = 1

# Driver code 
if __name__ == "__main__": 

    arr = [2, 3] 
    N = len(arr) 

    # maximum size of x 
    MAX = 1000

    # to check whether x is possible or not 
    ispossible = [0] * MAX

    check(arr, N) 
    x = 7

    if ispossible[x]: 
        print(x, "is possible.") 
    else: 
        print(x, "is not possible.")