代码之家  ›  专栏  ›  技术社区  ›  alex108

如何改进效率低下的解决方案?[复制]

  •  0
  • alex108  · 技术社区  · 5 年前

    solution 它使用动态规划方法。根据他的定性描述,我用python翻译了他的解决方案。我正试图优化这个更大的列表,这会占用我很多内存。有人能推荐一些优化或其他技术来解决这个问题吗?下面是我在python中的尝试:

    import random
    from time import time
    from itertools import product
    
    time0 = time()
    
    # create a zero matrix of size a (row), b(col)
    def create_zero_matrix(a,b):
        return [[0]*b for x in xrange(a)]
    
    # generate a list of size num with random integers with an upper and lower bound
    def random_ints(num, lower=-1000, upper=1000):
        return [random.randrange(lower,upper+1) for i in range(num)]
    
    # split a list up into N and P where N be the sum of the negative values and P the sum of the positive values.
    # 0 does not count because of additive identity
    def split_sum(A):
        N_list = []
        P_list = []
        for x in A:
            if x < 0:
                N_list.append(x)
            elif x > 0:
                P_list.append(x)
        return [sum(N_list), sum(P_list)]
    
    # since the column indexes are in the range from 0 to P - N
    # we would like to retrieve them based on the index in the range N to P
    # n := row, m := col
    def get_element(table, n, m, N):
        if n < 0:
            return 0
        try:
            return table[n][m - N]
        except:
            return 0
    
    # same definition as above
    def set_element(table, n, m, N, value):
        table[n][m - N] = value
    
    # input array
    #A = [1, -3, 2, 4]
    A = random_ints(200)
    
    [N, P] = split_sum(A)
    
    # create a zero matrix of size m (row) by n (col)
    #
    # m := the number of elements in A
    # n := P - N + 1 (by definition N <= s <= P)
    #
    # each element in the matrix will be a value of either 0 (false) or 1 (true)
    m = len(A)
    n = P - N + 1;
    table = create_zero_matrix(m, n)
    
    # set first element in index (0, A[0]) to be true
    # Definition: Q(1,s) := (x1 == s). Note that index starts at 0 instead of 1.
    set_element(table, 0, A[0], N, 1)
    
    # iterate through each table element
    #for i in xrange(1, m): #row
    #    for s in xrange(N, P + 1): #col
    for i, s in product(xrange(1, m), xrange(N, P + 1)):
        if get_element(table, i - 1, s, N) or A[i] == s or get_element(table, i - 1, s - A[i], N):
            #set_element(table, i, s, N, 1)
            table[i][s - N] = 1
    
    # find zero-sum subset solution
    s = 0
    solution = []
    for i in reversed(xrange(0, m)):
        if get_element(table, i - 1, s, N) == 0 and get_element(table, i, s, N) == 1:
            s = s - A[i]
            solution.append(A[i])
    
    print "Solution: ",solution
    
    time1 = time()
    
    print "Time execution: ", time1 - time0
    
    0 回复  |  直到 14 年前
        1
  •  5
  •   Martin Carames Abente    14 年前

    我不太确定你的解是精确解还是PTA(poly-time approximation)。

    也就是说,每个已知的(精确的)算法对输入的大小都有指数时间行为。

    也就是说,如果你能在0.01纳秒内处理1个操作,那么对于一个包含59个元素的列表,它需要:

    2^59 ops -->     2^59     seconds -->     2^26      years -->      1 year
                --------------           ---------------
                10.000.000.000           3600 x 24 x 365
    

    另一方面,如果你用集合中数的值的界来限制问题(另一个问题),那么问题的复杂性就降低到多项式时间。但即使这样,所消耗的内存空间也将是一个非常高阶的多项式。
    甚至比你硬盘上的几兆字节还要大。

    (对于集合中元素值的边界的小值)

    也许这就是你的动态规划算法的情况。

    在我看来,您在构建初始化矩阵时使用了1000的边界。

    祝你好运!

        2
  •  5
  •   skorks    14 年前

    Hacker News上有人提出了以下解决问题的方法,我很喜欢。它正好在python中:):

    def subset_summing_to_zero (activities):
      subsets = {0: []}
      for (activity, cost) in activities.iteritems():
          old_subsets = subsets
          subsets = {}
          for (prev_sum, subset) in old_subsets.iteritems():
              subsets[prev_sum] = subset
              new_sum = prev_sum + cost
              new_subset = subset + [activity]
              if 0 == new_sum:
                  new_subset.sort()
                  return new_subset
              else:
                  subsets[new_sum] = new_subset
      return []
    

    我花了几分钟用它,效果很好。

        3
  •  1
  •   mitchus    14 年前

    有一篇关于优化python代码的有趣文章 here . 基本上,主要的结果是你应该内联你的频繁循环,所以在你的例子中,这意味着不要调用 get_element 每次循环两次,将该函数的实际代码放入循环中,以避免函数调用开销。

    希望有帮助!干杯

        4
  •  1
  •   Luka Rahne    14 年前

    ,第一次吸引眼球

    def split_sum(A):
      N_list = 0
      P_list = 0
      for x in A:
        if x < 0:
            N_list+=x
        elif x > 0:
            P_list+=x
      return [N_list, P_list]
    

    一些建议:

    1. 尝试使用1D list和bitarray来减少内存占用(http://pypi.python.org/pypi/bitarray)所以只需更改get/set函数。这样至少可以减少64个内存占用(列表中的整数是指向整型的指针,所以可以是因子3*32)

    2. 避免使用try-catch,但在开始时找出合适的范围,您可能会发现您将获得巨大的速度。

        5
  •  0
  •   devDeejay    9 年前

    from itertools import chain, combinations
    def powerset(iterable):
        s = list(iterable)
        return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
    
    

    nums = input("Enter the Elements").strip().split() inputSum = int(input("Enter the Sum You want"))

    for i, combo in enumerate(powerset(nums), 1): sum = 0 for num in combo: sum += int(num) if sum == inputSum: print(combo)

    Enter the Elements 1 2 3 4
    Enter the Sum You want 5
    ('1', '4')
    ('2', '3')
        6
  •  0
  •   Eric Aya    8 年前

    def subsetsum(cs,k,r,x,w,d):
        x[k]=1
        if(cs+w[k]==d):
            for i in range(0,k+1):
    
                if x[i]==1:
                    print (w[i],end=" ")
            print()
    
        elif cs+w[k]+w[k+1]<=d :
            subsetsum(cs+w[k],k+1,r-w[k],x,w,d)
    
        if((cs +r-w[k]>=d) and (cs+w[k]<=d)) :
            x[k]=0
            subsetsum(cs,k+1,r-w[k],x,w,d)
    #driver for the above code
    w=[2,3,4,5,0]
    x=[0,0,0,0,0]
    
    subsetsum(0,0,sum(w),x,w,7)