Move 2015 out of the way.

This commit is contained in:
Bert Peters
2016-12-01 11:25:19 +01:00
parent a75d14ec17
commit b37fd44fa7
50 changed files with 0 additions and 0 deletions

26
2015/day-17/README.md Normal file
View File

@@ -0,0 +1,26 @@
# Day 17 efficient solution
Day 17 is an instance of the subset sum problem. This problem asks whether for
a (multi)set of integers *V*, there is a non-empty subset of integers summing up to
exactly *s*. This problem is NP-complete.
The brute force approach of this is trying every possible set in the powerset
of *V* to see if they match. This is inpractical however, because a powerset of
a set of size *n* contains 2<sup>2</sup> sets.
In the exercise, we have 20 buckets, and 2<sup>20</sup> is still
brute-forcable. There is a smarter approach.
We split the list of buckets in two lists of (approximately) the same size. We
then take the powersets of those two lists and compute the sum for each entry.
This leaves us with a total of 2<sup>n / 2 + 1</sup> entries. We then sort both
sublists on the total value of each entry.
Finally, we iterate of the first list, and use binary search to see whether
there is an appropriately sized entry in the second list. This gives us a final
complexity of *n* times 2<sup>*n*/2</sup>, allowing the solution to be computed
instantly.
The algorithm above can be modified to find all combinations, not just one, in
time proportional to the number of solutions. This is implemented in the final
program.

20
2015/day-17/input.txt Normal file
View File

@@ -0,0 +1,20 @@
33
14
18
20
45
35
16
35
1
13
18
13
50
44
48
6
24
41
30
42

62
2015/day-17/solution.py Normal file
View File

@@ -0,0 +1,62 @@
from __future__ import print_function, division
import fileinput
from collections import defaultdict
import bisect
def value(buckets, choice):
total = 0
for value in buckets:
if choice % 2 == 1:
total += value
choice //= 2
return total
def ones(x):
n = 0
while x > 0:
if x % 2:
n += 1
x //= 2
return n
def partition(a_list):
pivot = len(a_list) // 2
return a_list[:pivot], a_list[pivot:]
def partitionList(buckets):
result = [(value(buckets, x), ones(x)) for x in range(1 << len(buckets))]
result.sort()
return result
buckets = []
for line in fileinput.input():
buckets.append(int(line))
partition1, partition2 = partition(buckets)
values1 = partitionList(partition1)
values2 = partitionList(partition2)
possible = defaultdict(lambda: 0)
i = 0
target = 150
for entry in values1:
i = bisect.bisect_left(values2, (target - entry[0], 0))
while i < len(values2) and entry[0] + values2[i][0] == target:
possible[entry[1] + values2[i][1]] += 1
i += 1
print("Total possibilities:", sum(possible.values()))
print("Minimal possibilities:", possible[min(possible.keys())])