Reputation: 548
There is a task that needs to be executed by two people every day and there is a team of people available.
The idea is to assign two different people to that tasks in a way that every possible combination is assigned at least once.
Also, ideally, any particular person should be assigned as far as possible from the previous assigned day.
Example:
Given team: A, B, C, D, E, F
The schedule for the task could be:
Day 1 = A, D
Day 2 = B, E
Day 3 = C, F
Day 4 = A, E
Day 5 = B, F
Day 6 = C, D
Day 7 = A, F
Day 8 = B, D
Day 9 = C, E
Day 10 = E, D
Day 11 = B, E
Day 12 = C, A
...
Note that the same letter is assigned with certain distance from the previous time. For example A is assigned to days 1, 4, 7, 12 and D is assigned to days 1, 6, 8, 10. Note also that all possible combinations are present.
Currently, I can "manually" combine and sort the pairs for small teams (6 - 8 people), but for bigger teams I haven't been able to come up with an algorithm.
Is there an algorithm that can help me?
Bonus Point:
At any point, a person can become "inactive", and so he should be replaced by someone else following the rules.
Thank you very much!
Upvotes: 2
Views: 1665
Reputation: 16090
My approach is like this.
This way, it is easy to eliminate pairs with absent members, you just exclude it from the list of possible pairs. And when someone comes back, they will be likely to be next in line because of least of assignments so far. This should keep the amount of work stay as close to equlibrium as possible.
It is probably less predictable than round robin, but it does deal better with random perturbations to the planned queue. It is also slower, as it is linear for each pick, round-robin does everything, and picking is constant, but I guess it is acceptable.
Skeleton python code:
import itertools as it
def pick_pair(pairs):
pair = min(pairs, key=lambda p: p[0]['count'] + p[1]['count'])
pair[0]['count'] += 1
pair[1]['count'] += 1
return pair
team = [ {'name' : name, 'count' : 0} for name in range(6) ]
pairs = list(it.combinations(team,2))
day = 0
for i in range(len(pairs)):
print("Day {}: {}".format(day, pick_pair(pairs)))
day += 1
To account for absent team-members you have to filter the pairs
passed to pick_pair
.
Upvotes: 1
Reputation: 65506
The following round-robin scheduling algorithm described on Wikipedia solves the non-bonus part of your question. The idea is to pair like
0 1 2 3 4
5 6 7 8 9
getting pairs 05 16 27 38 49
, and then rotate clockwise all but 0
0 5 1 2 3
6 7 8 9 4
getting pairs 06 57 18 29 34
, and then repeat
0 6 5 1 2
7 8 9 4 3
etc. Although this algorithm was designed for parallel round-robin tournaments, it happens to have the property that, because the clockwise rotation doesn't move any element very far horizontally, the gaps between occurrences of each particular number is fairly consistent.
To answer your bonus question, I would recommend experimenting with local search -- there's no way that random disruptions are going to let any ahead-of-time combinatorial solution work properly.
Upvotes: 5