1

Using Django to develop a small scheduling web application where people are assigned certain times to meet with their superiors. Employees are stored as models, with a OneToMany relation to a model representing time ranges and day of the week where they are free. For instance:

Bob: (W 9:00, 9:15), (W 9:15, 9:30), ... (W 15:00, 15:20)
Sarah: (Th 9:05, 9:20), (F 9:20, 9:30), ... (Th 16:00, 16:05)
...
Mary: (W 8:55, 9:00), (F 13:00, 13:35), ... etc

My program allows a basic schedule setup, where employers can choose to view the first N possible schedules with the least gaps in between meetings under the condition that they meet all their employees at least once during that week. I am currently generating all possible permutations of meetings, and filtering out schedules where there are overlaps in meeting times. Is there a way to generate the first N schedules out of M possible ones, without going through all M possibilities?

Clarification: We are trying to get the minimum sum of gaps for any given day, summed over all days.

zhuyxn
  • 6,671
  • 9
  • 38
  • 44
  • Scheduling problems are, in general, NP-complete (or some other NP class, can't recall), and cannot be solved without trying all possible combinations. If you don't need perfect accuracy, greedy heuristics can perform decently. But, I'm not writing this as an answer yet as I'm not sure I understand exactly what the question is - are you trying to find the optimal `N` schedules possible, with respect to minimizing gaps? – ceyko Jan 02 '13 at 03:06
  • Ah I see. Yes, I am attempting to return the top N schedules with the least amount of gaps out of M possible ones. Are there any heuristics you would suggest in terms of returning schedules which are close to the gap minimum? – zhuyxn Jan 02 '13 at 03:15
  • Another clarification question: Essentially, you have a list of all employees and their availabilities, and you want to choose one time for each employee, such that none of the times overlap, and the sum of the gaps between each consecutive meeting is minimized, correct? Do we care about gap between the last meeting of one day and the first meeting the next day - or are we trying to get the minimum sum of the gaps for a day, summed over all days? (This part may not matter for the overal complexity, but I just want to confirm.) – ceyko Jan 02 '13 at 03:17

2 Answers2

0

I would use a search algorithm, like A-star, to do this. Each node in the graph represents a person's available time slots and a path from one node to another means that node_a and node_b are in the partial schedule.

Another solution would be to create a graph in which the nodes are each person's availability times and there is a edge from node_a to node_b if the person associated with node_a is not the same as the person associated with node_b. The weight of each node is the amount of time between the time associated with the two nodes.

After creating this graph, you could generate a variant of a minimum spanning tree from the graph. The variant would differ from MSTs in that:

  1. you'll only add a node to the MST if the person associated with the node is not already in the MST.
  2. you finish creating the MST when all persons are in the MST.

The minimum spanning tree generated would represent a single schedule.

To generate other schedules, remove all the edges from the graph which are found in the schedule you just created and then create a new minimum spanning tree from the graph with the removed edges.

David Weiser
  • 5,190
  • 4
  • 28
  • 35
  • Interesting idea, but if we have a node for each person-time tuple, wouldn't the MST select all the times for every person in its schedule, since it necessarily hits all nodes? – ceyko Jan 02 '13 at 03:44
  • Dah! Good call, I hadn't thought of that. One possibility is to only add a node to the MST if the person associated with the node is not in the MST. Also, you'd need to stop the creation of the MST as soon as all persons are found in the graph. At this point, however, it is not an MST. I'll update my answer accordingly. – David Weiser Jan 02 '13 at 03:53
0

In general, scheduling problems are NP-hard, and while I can't figure out a reduction for this problem to prove it such, it's quite similar to a number of other well-known NP-complete problems. There may be a polynomial-time solution for finding the minimum gap for a single day (though I don't know it off hand, either), but I have less hopes for needing to solve it for multiple days. Unfortunately, it's a complicated problem, and there may not be a perfectly elegant answer. (Or, I'm going to kick myself when someone posts one later.)

First off, I'd say that if your dataset is reasonably small and you've been able to compute all possible schedules fairly quickly, you may just want to stick with that solution, as all others will be approximations, and could possibly end up running slower, if the constant factor of their running time is large. (Meaning that it doesn't grow with the size of the dataset, so it will relatively be smaller for a large dataset.)

The simplest approximation would be to just use a greedy heuristic. It will almost assuredly not find the optimum schedules, and may take a long time to find a solution if most of the schedules are overlapping, and there are only a few that are even valid solutions - but I'm going to assume that this is not the case for employee times.

Start with an arbitrary schedule, choosing one timeslot for each employee at random. For each iteration, pick one employee and change his timeslot to the best possible time, with respect to the rest of current schedule. Repeat this process until your satisfied with the result - when it isn't improving quickly enough anymore or has taken too long. You're probably not going to want to repeat until you can't make any more changes that improve the schedule, since this process will likely loop for most data.

It's not a great heuristic, but it should produce some reasonable schedules, and has a lot of room for adjustment. You may want to always try to switch overlapping times first before any others, or you may want to try to flip the employee who currently contributes to the largest gap, or maybe eliminate certain slots that you've already tried. You may want to sometimes allow a move to a less optimal solution in hopes that you're at a local minima and want to get out of it - some randomness can also help with this. Make sure you always keep track of the best solution you've seen so far.

To generate more schedules, the most obvious thing would be to just start the process over with a different random schedule. Or, maybe flip a few arbitrary times from the previous solution you found, and repeat from there.

Edit: This is all fairly related to genetic algorithms, and you may want to use some of the ideas I presented here in a GA.

ceyko
  • 4,822
  • 1
  • 18
  • 23