I am trying to solve the following problem, which I am quite sure has a solution. I am not able to disclose too much information,so I formulated it general term and came up with the following allegory. I present you here the sleeping monks problem.
Imagine a monastery where 12 monks sleep, eat, pray, or work outside the monastery. Each monk, needs to sleep 8 or 6 hours per night. Each monk has X amount where he has to work in the garden, the stall or herd the sheep (e.g, activities outside the monastery) and Y hours hangs around within the walls of the monastery during these Y hours each monk is either hanging around (e.g. praying, eating, consuming beer) or he is sleeping S hours (Y is always bigger the S).
The head of this monastery asks if there is a possible way to find a best possible sleeping arrangement such that the number of beds can be reduced, and that each monks get its required sleeping.
The input data I have for the problem is given in the following form:
time_slots_in_monastery = [
# time of the day
#14 16 18 20 22 24 2 4 6 8 10 12
(0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
(0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0),
(0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0),
(0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0),
]
Each row represents 1 monk. The digit 1 represents a time slot inside the monastery, and 0 represents a time where the monk is outside.
In addition I have a vector containing the sleeping requirements of each monk.
required_sleeping = [4, # number of sleeping slots , each one is 2 hours.
3,
3,
4,
4,
4,
4,
3,
3,
3,
3,
3]
The current, and really not satisfying sleeping, solution is:
solution = [
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
]
# total beds:
# 0, 0, 12, 12, 12, 5, 0, 0 , 0, 0, 0, 0
All monks go to sleep at 6PM. But if we make monks 11 and 12 use the same bed we can reduce the number of beds to 11. And even better, monks 1 and 2 can also share their bed, then we reduce the number of beds to 10.
better_solution = [
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
]
Right now with 12 monks, the problem can be brute forced, but in reality I have about 50 monks and the time resolution is 5 minutes, and not 2 hours. Hence, I am looking for a way to find a way to solve the problem in an f-minimum-search style or any other way which is not brute force.
I present here my brute force solution in Python:
import pprint
time_slots_in_monastery = [
# time of the day
#14 16 18 20 22 24 2 4 6 8 10 12
(0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
(0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0),
(0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0),
(0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0),
(0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0),
]
required_sleeping = [4,
3,
3,
4,
4,
4,
4,
3,
3,
3,
3,
3]
def make_new_bed(rl):
bed = '0' * rl
return bed
def search_in_beds(beds, rl, sleep_time, first, last):
sleep_slots = '0' * sleep_time
sleep = '1' * sleep_time
index = False
for cn, bed in enumerate(beds):
try:
index = bed[first:last+1].index(sleep_slots)
index += first
bed = bed[:first] + bed[first:last+1].replace(sleep_slots, sleep, 1) + bed[last+1:]
beds[cn] = bed
print()
print('monastery time from: %s to: %s' % (first, last))
print('this monk found a place in bed(%s) from (%s) to (%s)' % (cn, index, index + sleep_time-1))
print('bed(%s) time: %s ' % (cn, bed))
except:
"""
I did not found a free time in this bed
"""
pass
if index:
return index, index + sleep_time - 1
#adding a bed and searching again
beds.append(make_new_bed(rl))
return search_in_beds(beds, rl, sleep_time, first, last)
def monks_beds(t, rsleep, rl=12):
beds = []
output = []
for cn, i in enumerate(t):
sleep_time = rsleep[cn]
first = i.index(1)
last = len(i) - 1 - i[::-1].index(1)
first, last = search_in_beds(beds, rl, sleep_time, first, last)
out = rl * '0'
out = out[:first] + sleep_time * '1' + out[last:]
output.append([int(x) for x in out])
return beds
print('time_slots_in_monastery:')
pprint.pprint(time_slots_in_monastery)
print('required_sleeping')
pprint.pprint(required_sleeping)
pprint.pprint(monks_beds(time_slots_in_monastery, required_sleeping))