101 lines
2.8 KiB
C#
101 lines
2.8 KiB
C#
using Core.Entities;
|
|
|
|
namespace Core.Calculation;
|
|
public class TeamScheduler_DecisionTree
|
|
{
|
|
private readonly IList<Student> _students;
|
|
private readonly IList<Team> _teams;
|
|
|
|
private readonly int _timeSlotCount;
|
|
|
|
public TeamScheduler_DecisionTree(IList<Team> teams, int timeSlotCount)
|
|
{
|
|
_timeSlotCount = timeSlotCount;
|
|
_teams = teams;
|
|
_students = teams.SelectMany(t => t.Students).Distinct().ToList();
|
|
}
|
|
|
|
public IList<Team>[] Solve()
|
|
{
|
|
var timeSlots = new IList<Team>[_timeSlotCount];
|
|
for (var i = 0; i < _timeSlotCount; i++)
|
|
timeSlots[i] = new List<Team>();
|
|
|
|
foreach (var team in _teams.OrderByDescending(t => t.Students.Count))
|
|
{
|
|
// get overlapping students in each timeslot
|
|
var overlaps
|
|
= (from tsi in Enumerable.Range(0, timeSlots.Length)
|
|
let ts = timeSlots[tsi]
|
|
let tss = ts.SelectMany(t => t.Students).Distinct()
|
|
select Tuple.Create(tsi, team.Students.Count(tss.Contains)))
|
|
.OrderBy(t => t.Item2)
|
|
.ThenBy(t => timeSlots[t.Item1].Count);
|
|
|
|
timeSlots[overlaps.First().Item1].Add(team);
|
|
}
|
|
return timeSlots;
|
|
}
|
|
|
|
public IList<Team>[] SolveRecursive()
|
|
{
|
|
// initialize time slots
|
|
var timeSlots = new IList<Team>[_timeSlotCount];
|
|
for (var i = 0; i < _timeSlotCount; i++)
|
|
timeSlots[i] = new List<Team>();
|
|
|
|
return
|
|
(from i in Enumerable.Range(1, 5)
|
|
let solution = Recursive(timeSlots, _teams, i)
|
|
let overlapCount = Team.GetStudentTeamOverlapCount(solution)
|
|
orderby overlapCount
|
|
select solution).First();
|
|
}
|
|
|
|
private static IList<Team>[] CopyTimeSlots(IList<Team>[] timeSlots)
|
|
{
|
|
return timeSlots.Select(ts => (IList<Team>)new List<Team>(ts)).ToArray();
|
|
}
|
|
|
|
private static IList<Team>[] Recursive(IList<Team>[] timeSlots, IList<Team> teams, int overlapTriesStudents = 4)
|
|
{
|
|
if (!teams.Any())
|
|
return timeSlots;
|
|
|
|
var overlapsTries =
|
|
(from team in teams.OrderByDescending(t => t.Students.Count).Take(overlapTriesStudents)
|
|
//from ts in timeSlots
|
|
from tsi in Enumerable.Range(0, timeSlots.Length)
|
|
let ts = timeSlots[tsi]
|
|
let tss = ts.SelectMany(t => t.Students)
|
|
select Tuple.Create(ts, tsi, team, team.Students.Count(tss.Contains)))
|
|
.OrderBy(t => t.Item4)
|
|
.ThenBy(t => t.Item1.Count);
|
|
|
|
var minOverlaps =
|
|
(from o in overlapsTries
|
|
group o by o.Item4
|
|
into oo
|
|
orderby oo.Key
|
|
select oo).First();
|
|
|
|
var first = minOverlaps.First();
|
|
|
|
var results = new List<Tuple<IList<Team>[], int>>();
|
|
|
|
foreach (var minOverlap in minOverlaps)
|
|
{
|
|
var timeSlotsAfterAdd = CopyTimeSlots(timeSlots);
|
|
timeSlotsAfterAdd[first.Item2].Add(first.Item3);
|
|
var remainingTeams = teams.Where(t => t != first.Item3).ToList();
|
|
|
|
var result = Recursive(timeSlotsAfterAdd, remainingTeams);
|
|
|
|
results.Add(Tuple.Create(result, Team.GetStudentTeamOverlapCount(result)));
|
|
if (minOverlap.Item4 == 0)
|
|
break;
|
|
}
|
|
|
|
return results.OrderByDescending(r => r.Item2).First().Item1;
|
|
}
|
|
} |