¿Cómo hacer que Python se detenga una vez que el producto objetivo se encuentra en el subconjunto?

8

He estado aprendiendo Python para mi pasatiempo y la investigación empírica en problemas NP-completos como Subset Product. El algoritmo que tengo funciona, pero no lo está haciendo de la manera que pretendo hacerlo.

Lo que intento hacer es detener las herramientas de iterto combinationsuna vez que llegue a un producto de subconjunto de la variable de entrada target. Esto hará que el código sea más rápido. El código está en la etapa de pulido, por lo que hay una lista innecesariares_2

Aquí está el bucle.

res_2 = [];
for i in range(1, len(s)+1):

   var = (findsubsets(s, i))   
   kk = list(map(numpy.prod, var))
   res_2.append(kk)
   if target in kk:
     print('yes')
     print(var)
     break

Este es el resultado que no quiero. Tenga en cuenta que el script no se detendrá en (4, 4). Es una pérdida de recursos continuar comprobando todas las combinaciones una vez que un objetivo es "alcanzado".

Enter numbers WITH SPACES: 4 4 3 12
enter target integer:
16
yes
[(4, 4), (4, 3), (4, 12), (4, 3), (4, 12), (3, 12)]
 kk
[16, 12, 48, 12, 48, 36]

Mi salida prevista es parar en (4, 4) si es el primer "golpe". Lo mismo para cualquier otro subconjunto como (1,2,3) o (1,2,3 --- cualquier longitud). Preferiría que el script continúe hasta que pueda encontrar un éxito. Una vez que encuentra el golpe, se detiene, porque esto mejoraría la velocidad del algoritmo.

Guión completo a continuación

# Naive Subset-Product solver
# with python's itertools

import itertools 
import numpy

s = list(map(int, input('Enter numbers WITH SPACES: ').split(' ')))
print('enter target integer: ')
target = int(input())


if s.count(target) > 0:
   print('yes')
   quit()

if target > numpy.prod(s):
  print('sorry cant be bigger than total product of s')
  quit()


def findsubsets(s, n): 
    return list(itertools.combinations(s, n)) 

# Driver Code 
n = len(s)

# This code snippet is a for loop. It also is intended to cut down execution
# time once it finds the target integer. (instead of creating all combinations)

res_2 = [];
for i in range(1, len(s)+1):

   var = (findsubsets(s, i))   
   kk = list(map(numpy.prod, var))
   res_2.append(kk)
   if target in kk:
     print('yes')
     print(var)
     break

Pregunta

¿Cómo hago para que esto funcione para aumentar la velocidad del algoritmo? ¿Qué trucos pitónicos solucionarían mi problema? ¿Hay una forma más corta de hacer esto?

Travis Wells
fuente

Respuestas:

3

Es prematuro convertir el combinationsvalor de retorno de las herramientas de iterto en a list, especialmente cuando intenta salir temprano y evitar demasiada sobrecarga. Por lo general, hay una buena razón por la cual las funciones de la biblioteca devuelven iteradores en lugar de listas completamente realizadas.

Aquí hay una sugerencia:

def findsubsets(s, n): 
    return itertools.combinations(s, n)

def find_subset(target,nums):
    for i in range(1,len(nums)+1):
        for ss in findsubsets(nums, i):
            if np.prod(ss) == target:
                prodstr = '*'.join(str(num) for num in ss)
                print(f"{target} = {prodstr}")
                return ss
    return None

find_subset(96,[1,6,2,8])

Dado que findsubsetses una sola línea, es algo cuestionable tenerla como una función independiente (básicamente solo estamos usando alias combinationsque podría haberse hecho con una import X as Ydeclaración). En cualquier caso, esto debería detenerse temprano sin acaparar demasiada RAM con entradas más grandes.

smarchese
fuente