Reputation: 31
Here is my problem:
There are N tennis players in the bucket
They play matches every week
Each player has its list of possible opponents from the bucket
Each player specifies:
Monday 8h, courts 1,2 and 3 Tuesday 10h court 2 etc
I need to build the algorithm to create optimized schedule:
Hi,
What kind of algorithm I need here? Is it a linear programing model or something else?
In an ideal world - I would build the model in json and send it to some Cloud optimisation engine like Gurabi to get the solution back. Or any other tool that you suggest.
Thanks Darko
Upvotes: 2
Views: 63
Reputation: 20596
The first thing to do is to check if there is a feasible solution. You need to check if the possible opponents of every player share times when they can play at a time when there is a court available.
Now you have an agent to task assignment problem which can be solved using the maximum flow algorithm ( https://en.wikipedia.org/wiki/Maximum_flow_problem ).
The "tasks" are the opponent pair and time combinations found by the feasibility check
The "agents" are the court times.
Of course, the application of the max flow algorithm must be adjusted to include the special constraints of your problem.
Each player to play at least once
Out of the box, the algorithm will optimize the total number of games played, even if some players do not get to play. Suggestion: Run the algorithm without this constraint and check for players without a game. Brute force those players to play a games and remove the players and the court time used from the problem and re-run the algorithm
prioritize certain players by different criteria
I do not know what this means. If Player A is "prioritized" and Player B is not, what is the difference in how A and B are handled?
prioritize certain times
I do not know what this means. If Wednesday morning is "prioritized" but not Wednesday afternoon, what difference does this make?
Here is a setup that tests code is working for a simple sanity test
void generate1()
{
// generate players
thePlayers.emplace_back("pA");
thePlayers.emplace_back("pB");
// add possible opponents
thePlayers[0].addOpp("pB");
thePlayers[1].addOpp("pA");
// add available times
thePlayers[0].addTime(1);
thePlayers[0].addTime(3);
thePlayers[0].addTime(2);
thePlayers[1].addTime(2);
thePlayers[1].addTime(3);
// generate court times
theCourts.emplace_back(1);
theCourts.emplace_back(2);
theCourts.emplace_back(3);
}
Here is the C++ code that checks the setup is feasible and generates the tasks for the maximum flow algorithm
/**
* @brief Check for feasibility
*
* i.e. every player has at least one opponent with a matching available time and possible court time
*/
void check()
{
// loop over players
int pi = -1;
for (auto &p : thePlayers)
{
pi++;
// assume that player has no possible opponent with matching time
bool ok = false;
// loop over player available times
for (int t : p.myTimes)
{
// loop over player possible opponents
for (auto &os : p.myOpps)
{
// loop over opponents available times
int oi = findPlayer(os);
for (int ot : thePlayers[oi].myTimes)
{
if (t == ot)
{
// loop over court times
for (auto &c : theCourts)
{
if (t == c.myTime)
{
// found a match with opponent and court
ok = true;
// create a task for each feasible pair
// only record task when player 1 index less than player 2
if (pi < oi) {
theTasks.emplace_back(p, thePlayers[oi], t);
}
}
}
}
}
}
}
if (!ok)
{
std::cout << "Cannot find opponent for " << p.myName << "\n";
exit(1);
}
}
std::cout << "found feasible opponents for all players\n";
cTask::displayAll();
}
here is the output
found feasible opponents for all players
pA v pB at 3
pA v pB at 2
Here is the C++ code to apply the maximum flow algorithm. It uses the method from the pathfinder graph theory library https://github.com/JamesBremner/PathFinder
void maxflow()
{
// setup the flow graph
raven::graph::sGraphData gd;
gd.g.directed();
for (auto &c : theCourts)
for (auto &t : theTasks)
if (t.myt == c.myTime)
{
// Game can be played on this court
gd.g.add(c.myName, t.myName);
}
// apply the maxflow algorithm, allocating games to courts
auto ga = raven::graph::alloc(gd);
// display game schedule
std::cout << "\nGame Schedule\n";
for (int ei = 0; ei < ga.edgeCount(); ei++)
{
auto t = gd.g.userName(gd.g.dest(ei));
theTasks[atoi(t.substr(4).c_str())].display();
}
}
Output is
Game Schedule
pA v pB at 2 on cA
Complete application code at https://github.com/JamesBremner/so78357533
You have not answered my questions about the priorities :-(
Time Priorities
My best guess for the time priorities is that when two players have a choice of court times, they will be scheduled at the time with the highest priority. Something like this can be implemented easily by presorting the "tasks" before doing the allocation in order of decreasing priority.
Like this:
Same priority for all times
found feasible opponents for all players
pA v pB at 1 on cA
pA v pB at 2 on cA
Game Schedule
pA v pB at 1 on cA
Time 2 at high priority
found feasible opponents for all players
pA v pB at 1 on cA
pA v pB at 2 on cA
Game Schedule
pA v pB at 2 on cA
Player Priority
I cannot guess what you require for the player priority feature. Please edit you question to clarify this.
Upvotes: 1