No será eficiente, pero puede resolver este
en tiempo polinomial
con un algoritmo de programación dinámico directo.
El grado del polinomio dependerá de la cantidad de tamaños diferentes que tenga.
He incluido una implementación que para 3 tamaños diferentes será O(n1 * n2 * n3 * (C/s2) * (C/s3) * ((n1*s1 + n2*s2 + n3*s3)/C))
con una constante bastante repugnante. (Esa cifra se debe al hecho de que el número de patrones distintos de disponibilidad es O(n1 * n2 * n3)
y para cada uno generamos O((C/s2) * (C/s3))
posibles siguientes contenedores para probar, para cada uno de los cuales tenemos que trabajar con un conjunto de contenedores cuyo tamaño es O((n1*s1 + n2*s2 + n3*s3)/C))
. Una serie de optimizaciones de rutina podría acelerar masivamente este programa.)
#! /usr/bin/python
import heapq
def min_bins(bin_size, sizes, counts):
available = zip(sizes, counts)
available.sort(reverse=True)
seen = set([])
upcoming = [(0, available, [])]
while 0 < len(upcoming):
(n, available, bins) = heapq.heappop(upcoming)
for (bin, left) in bin_packing_and_left(bin_size, available):
new_bins = bins + [bin]
if 0 == len(left):
return new_bins
elif left not in seen:
heapq.heappush(upcoming, (n+1, left, new_bins))
seen.add(left)
def bin_packing_and_left(bin_size, available, top=True):
if 0 == len(available):
yield ((),())
else:
(size, count) = available[0]
available = available[1:]
for (bin, left, used) in bin_packing_and_left_size(bin_size, available):
can_use = (bin_size - used)/size
if count <= can_use:
yield(((size, count),) + bin, left)
elif 0 < can_use:
yield(((size, can_use),) + bin,
((size, count - can_use),) + left)
else:
yield(bin, ((size, count),) + left)
def bin_packing_and_left_size(bin_size, available):
if 0 == len(available):
yield ((),(), 0)
else:
(size, count) = available[0]
available = available[1:]
for (bin, left, used) in bin_packing_and_left_size(bin_size, available):
for i in range(1 + min(count, (bin_size - used)/size)):
if count == i:
yield(((size, count),) + bin, left, used + size * count)
elif 0 < i:
yield(((size, i),) + bin,
((size, count - i),) + left,
used + size * i)
else:
yield(bin, ((size, count),) + left, used)
answer = min_bins(23, (2, 3, 5), (20, 30, 40))
print len(answer)
print answer
¿Cuál es la pregunta? –
¿Tarea para qué clase exactamente? –
@Henk: No es una tarea de todos modos, dejé la universidad hace 6 años. Puede ser una pregunta tonta, pero no pude hacer sub-problemas por mi cuenta. –