A complete solution that calculates the whole way to make a conclusion. I use ints as characteristic sets for speed and memory usage: 19='0b10011' represents [A[0],A[1],A[4]]=[8,9,33] here.
A = [8, 9, 15, 15, 33, 36, 39, 45, 46, 60, 68, 73, 80, 92, 96] B =[183, 36, 231, 128, 137] def subsetsum(A,N): res=[[0]]+[[] for i in range(N)] for i,a in enumerate(A): k=1<<i stop=[len(l) for l in res] for shift,l in enumerate(res[:N+1-a]): n=a+shift ln=res[n] for s in l[:stop[shift]]: ln.append(s+k) return res res = subsetsum(A,max(B)) solB = [res[b] for b in B] exactsol = ~-(1<<len(A)) def decode(answer): return [[A[i] for i,b in enumerate(bin(sol)[::-1]) if b=='1'] for sol in answer] def solve(i,currentsol,answer): if currentsol==exactsol : print(decode(answer)) if i==len(B): return for sol in solB[i]: if not currentsol&sol: answer.append(sol) solve(i+1,currentsol+sol,answer) answer.pop()
For:
solve(0,0,[]) [[9, 46, 60, 68], [36], [8, 15, 39, 73, 96], [15, 33, 80], [45, 92]] [[9, 46, 60, 68], [36], [8, 15, 39, 73, 96], [15, 33, 80], [45, 92]] [[8, 15, 15, 33, 39, 73], [36], [9, 46, 80, 96], [60, 68], [45, 92]] [[9, 15, 33, 46, 80], [36], [8, 15, 39, 73, 96], [60, 68], [45, 92]] [[9, 15, 33, 46, 80], [36], [8, 15, 39, 73, 96], [60, 68], [45, 92]] [[15, 15, 73, 80], [36], [9, 39, 45, 46, 92], [60, 68], [8, 33, 96]] [[15, 15, 73, 80], [36], [8, 9, 33, 39, 46, 96], [60, 68], [45, 92]] [[45, 46, 92], [36], [15, 15, 60, 68, 73], [9, 39, 80], [8, 33, 96]] [[45, 46, 92], [36], [9, 15, 15, 39, 73, 80], [60, 68], [8, 33, 96]] [[45, 46, 92], [36], [8, 15, 39, 73, 96], [60, 68], [9, 15, 33, 80]] [[45, 46, 92], [36], [8, 15, 39, 73, 96], [15, 33, 80], [9, 60, 68]] [[45, 46, 92], [36], [8, 15, 39, 73, 96], [60, 68], [9, 15, 33, 80]] [[45, 46, 92], [36], [8, 15, 39, 73, 96], [15, 33, 80], [9, 60, 68]] [[15, 33, 39, 96], [36], [8, 15, 60, 68, 80], [9, 46, 73], [45, 92]] [[15, 33, 39, 96], [36], [8, 9, 15, 46, 73, 80], [60, 68], [45, 92]] [[15, 33, 39, 96], [36], [8, 15, 60, 68, 80], [9, 46, 73], [45, 92]] [[15, 33, 39, 96], [36], [8, 9, 15, 46, 73, 80], [60, 68], [45, 92]] [[8, 33, 46, 96], [36], [15, 15, 60, 68, 73], [9, 39, 80], [45, 92]] [[8, 33, 46, 96], [36], [9, 15, 15, 39, 73, 80], [60, 68], [45, 92]]
Note that if two 15 not in the same subset, the solution doubles.
Solves the unique problem of solving:
A=[1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049] B=[5010, 5035, 5060, 5085, 5110, 5135, 5160, 5185, 5210, 5235]
in one second. Unfortunately, it is not yet optimized enough for the problem (71,10).
Another one in the spirit of pure dynamic programming:
@functools.lru_cache(max(B)) def solutions(n): if n==0 : return set({frozenset()}) #{{}} if n<0 : return set() sols=set() for i,a in enumerate(A): for s in solutions(na): if i not in s : sols.add(s|{i}) return sols def decode(answer): return([[A[i] for i in sol] for sol in answer]) def solve(B=B,currentsol=set(),answer=[]): if len(currentsol)==len(A) : sols.append(decode(answer)) if B: for sol in solutions(B[0]): if set.isdisjoint(currentsol,sol): solve(B[1:],currentsol|sol,answer+[sol]) sols=[];solve()