2016-12-27 3 views
1

Существует определенное число C (C - целое число) и дается список чисел (назовем его N, все числа в списке N являются целыми числами). Моя задача состоит в том, чтобы найти количество возможностей для представления C.Оптимизация кода - количество комбинаций

Например:

вход:

C = 4 

N = [1, 2] 

выход:

3 

Потому что:

4 = 1 + 1 + 1 + 1 = 1 + 1 + 2 = 2 + 2 

Мой код работает очень хорошо для небольших чисел. Однако я понятия не имею, как я могу оптимизировать его, чтобы он работал и для больших целых чисел. Любая помощь будет оценена!

Существует мой код:

import numpy 
import itertools 
def amount(C): 
    N = numpy.array(input().strip().split(" "),int) 
    N = list(N) 
    N = sorted(N) 
    while C < max(N): 
     N.remove(max(N)) 
    res = [] 
    for i in range(1, C): 
     for j in list(itertools.combinations_with_replacement(N, i)): 
      res.append(sum(list(j))) 
    m = 0 
    for z in range (0, len(res)): 
     if res[z] == C: 
      m += 1 
    if N[0] == 1: 
     return m + 1 
    else: 
     return m 
+0

Здесь действительно нет необходимости в numpy. Во всяком случае, это замедлит вас. И вы все равно превращаете его в «список». Это бессмысленно. –

+0

Вы, кажется, хотите считать разделы: см. Https://en.wikipedia.org/wiki/Partition_(number_theory). –

+0

Вы можете сравнить свой код с npartitions в http://docs.sympy.org/dev/_modules/sympy/ntheory/partitions_.html. –

ответ

2

Сложность вашего алгоритма O(len(a)^С). Чтобы решить эту задачу более эффективно, используйте идеи dynamic programming.

Предполагается, что dp[i][j] соответствует количеству разделов i с использованием условий a[0], a[1], ..., a[j]. Массив a не должен содержать дубликатов. Это решение работает в O(C * len(a)^2) раз.

def amount(c): 
    a = list(set(map(int, input().split()))) 

    dp = [[0 for _ in range(len(a))] for __ in range(c + 1)] 
    dp[0][0] = 1 

    for i in range(c): 
     for j in range(len(a)): 
      for k in range(j, len(a)): 
       if i + a[k] <= c: 
        dp[i + a[k]][k] += dp[i][j] 

    return sum(dp[c]) 
+0

Это работает очень быстро! Спасибо за помощь. – Hendrra

+0

И это правильно - в моем массиве было много дубликатов. Можете ли вы объяснить, как работает последняя «если», пожалуйста? – Hendrra

+0

@ Hendrra это проверка границ. Этот оператор 'if' вообще не влияет на решение. – Andreikkaa

0

пожалуйста, проверьте этот первый: https://en.wikipedia.org/wiki/Combinatorics
также этот https://en.wikipedia.org/wiki/Number_theory
, если бы я тебя, я бы разделил с на п [я] первая и проверить гр не является номером из вашего примера: 4/1 = [4] => целочисленный счет 1
4/2 = [2] => целочисленный счетчик стал 2, затем разделил [2] на 1 + 1, если и только если 1 находится в наборе
что делать, если у вас есть 3 в комплекте [1,2,3 ], 4/3 просто вычесть 4-3 = 1, если 1 в наборе, счетчик увеличивается и для больших результатов я сделаю некоторое разбиение на основе набора

+0

Спасибо за все ссылки и новую идею. Это приятное решение (и это показывает много математики)! Я тоже это рассмотрю. Я думаю, однако, что это может быть немного медленнее, чем выше. – Hendrra