using Core.Entities; namespace Core.Calculation; public class TeamScheduler_DecisionTree { private readonly IList _students; private readonly IList _teams; private readonly int _timeSlotCount; public TeamScheduler_DecisionTree(IList teams, int timeSlotCount) { _timeSlotCount = timeSlotCount; _teams = teams; _students = teams.SelectMany(t => t.Students).Distinct().ToList(); } public IList[] Solve() { var timeSlots = new IList[_timeSlotCount]; for (var i = 0; i < _timeSlotCount; i++) timeSlots[i] = new List(); 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[] SolveRecursive() { // initialize time slots var timeSlots = new IList[_timeSlotCount]; for (var i = 0; i < _timeSlotCount; i++) timeSlots[i] = new List(); 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[] CopyTimeSlots(IList[] timeSlots) { return timeSlots.Select(ts => (IList)new List(ts)).ToArray(); } private static IList[] Recursive(IList[] timeSlots, IList 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[], 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; } }