Subset Product is an NP-complete problem and is my favorite problem. So, I've written a slightly smarter way of solving the problem.
- Will performance impact matter if I use multi-cpus and my GPU?
- Do my variable names make sense of what I'm doing?
- Is there a better way to write the for-loop under the variable "
max_combo"?
The Python Script
import itertools
from itertools import combinations
from functools import reduce
from operator import mul
from sys import exit
# Give TARGET whole number > 0 and give whole number divisors > 0 for D
# and see if a combination will have a total product equal to TARGET.
TARGET = int(input('enter target product: ' ))
D = input('Enter numbers: ').split(',')
D = list(set([int(a) for a in D]))
# Only divisors are allowed and must be sorted in ascending order for the algorithm to
# properly work.
D = sorted([i for i in D if TARGET % i==0])
# Using two-sum solution for two-product
two_prod_dict = {}
for a in range(0, len(D)):
if TARGET//int(D[a]) in two_prod_dict:
print('YES')
exit(0)
else:
two_prod_dict[int(D[a])] = a
if TARGET in D:
print('YES')
exit(0)
# A combination's total product cannot be larger
# than the TARGET. So this code section figures out
# the biggest combination size. (Doing my best to save running time)
max_combo = []
for a in D:
max_combo.append(a)
if reduce(mul,max_combo) >= TARGET:
if reduce(mul,max_combo) > TARGET:
max_combo.pop()
break
else:
break
This is the purpose of
max_comboand in this caselen(max_combo) = 5. Suppose TARGET = 120. Some of the divisors for D is 1,2,3,4,5,6,8,10,12. Notice that 5! = 120. (eg. (1,2,3,4,5) = TARGET) So, if you get a combination with six or more numbers it will go over because 6! > TARGET. Remember D is sorted in ascending order for the concept to work and it has no repeating numbers.
# Using any other divisor will go over TARGET.
# To save running time, do it only one time.
# Taking (1,2,3,4,6) will go over so stop at (1,2,3,4,5) (if there is one).
# So why waste running time?
for X in combinations(D, len(max_combo)):
if reduce(mul, X) == TARGET:
print('YES')
exit(0)
else:
break
# I'm hoping that smaller solutions
# are more likely than larger solutions so start
# with the smallest and work your way up.
for A in range(3, len(max_combo) + 1):
for X in combinations(D, A):
if reduce(mul, X) == TARGET:
print('YES',X)
exit(0)
print('NO')