public void ClearEvents() { //Формирование всех дат и доступных нарядов в них var dates = ПериодГрафика.Select(date => new ДатаГрафика { Date = date, Смены = Наряды.Where(nar => !nar.Усиление || Усиления.Contains(date)) .Where(nar => nar.Дни == WeekDays.Все || (nar.Дни == WeekDays.Выходные && Праздники.Contains(date)) || (nar.Дни == WeekDays.Будние && !Праздники.Contains(date))) .ToDictionary <Наряд, Наряд, Подразделение>(nar => nar, nar => null) }).ToList(); //Заполнение заблокированных нарядов foreach (var date in dates) { var find = ДатыГрафика.FirstOrDefault(gr => gr.Date == date.Date); if (find == null) { continue; } foreach (var nar in find.Блокировки) { date.Блокировки.Add(nar); if (!find.Смены.ContainsKey(nar)) { continue; } if (nar.Усиление && !Усиления.Contains(date.Date)) { continue; } if (Подразделения.Contains(find.Смены[nar])) { date.Смены[nar] = find.Смены[nar]; } } } //Перезапись старого графика новым //ДатыГрафика = new ObservableCollection<ДатаГрафика>(dates); ДатыГрафика.Clear(); foreach (var date in dates) { ДатыГрафика.Add(date); } ПересчитатьПодразделения(); }
/// <summary> /// Раскидывание подразделений по разным дням /// Чтобы в один день не было в наряде несколько человек с одного подразделения /// </summary> public void аскидать() { //Счётчик сделаных замен var count = 0; do { count = 0; var collisions = new Dictionary <ДатаГрафика, Dictionary <Наряд, Подразделение> >(); //Ищем повторы в днях foreach (var day in ДатыГрафика) { //Берём все заполненные незаблокированные наряды var nars = day.Смены.Where(pair => pair.Value != null && !day.Блокировки.Contains(pair.Key)).ToList(); //Сортируем по имени подразделения, чтобы легко найти дубликаты nars.Sort((p1, p2) => String.Compare(p1.Value.Название, p2.Value.Название, StringComparison.Ordinal)); var last = new KeyValuePair <Наряд, Подразделение>(); foreach (var nar in nars) { //Если два подряд одинаковые if (nar.Value == last.Value && last.Value != null) { if (!collisions.ContainsKey(day)) { collisions[day] = new Dictionary <Наряд, Подразделение>(); } //Добавляем в словарь повторов collisions[day][last.Key] = last.Value; collisions[day][nar.Key] = nar.Value; } last = nar; } } //Пробегаем по повторам foreach (var collision in collisions) { //Выделяем подобные дни var days = ДатыГрафика.Where(day => day.Holyday == collision.Key.Holyday).ToList(); //Выделяем подразделения с повторами foreach (var district in collision.Value.Select(vp => vp.Value).Distinct().ToList()) { var finded = false; //Выделяем наряды в которые в этот день идёт конкретное подразделение var naryads = collision.Value.Where(vp => vp.Value == district).Select(vp => vp.Key).ToList(); //Выделяем дни в которые данное подразделение ещё не стоит в наряде foreach (var vday in days.Where(d => !d.Смены.ContainsValue(district)).ToList()) { //Проверяем каждый день до первой замены if (finded) { break; } foreach (var nar in naryads) { //Ищем наряд в который уже идёт какое-нибудь подразделение var podob = vday.Смены.Where(vp => vp.Value != null //Наряд не заблокирован && !vday.Блокировки.Contains(vp.Key) //Такой же длительности && vp.Key.Длительность == nar.Длительность //И подразделение которое в него идёт не идёт в выбранный день && !collision.Key.Смены.ContainsValue(vp.Value) //И подразделение которое в него идёт может пойти в выбранный наряд && vp.Value.Наряды.Contains(nar)).ToList(); if (podob.Count <= 0) { continue; } finded = true; count++; //Меняем наряды местами collision.Key.Смены[nar] = podob[0].Value; vday.Смены[podob[0].Key] = district; break; } } } } } while (count > 0); //Пока есть что заменять }
public void GenerateEvents() { List <ДатаГрафика> best = null; double bestres = 0; for (int i = 0; i < 1000; i++) { ClearEvents(); var rand = new Random(); //Формирование конкретных нарядов на выходные var holypairs = new List <KeyValuePair <ДатаГрафика, Наряд> >(); foreach (var day in ДатыГрафика) { var day1 = day; foreach (var smen in day.Смены .Where(pair => !day1.Блокировки.Contains(pair.Key) && pair.Value == null && day1.Holyday) .Select(pair => pair.Key)) { holypairs.Insert(rand.Next(holypairs.Count), (new KeyValuePair <ДатаГрафика, Наряд>(day, smen))); } } //Сортировка нарядов по длительности в порядке убывания holypairs.Sort((pair, valuePair) => valuePair.Value.Длительность.CompareTo(pair.Value.Длительность)); аспределитьНаряды(holypairs); //Формирование конкретных нарядов var pairs = new List <KeyValuePair <ДатаГрафика, Наряд> >(); foreach (var day in ДатыГрафика) { var day1 = day; foreach (var smen in day.Смены .Where(pair => !day1.Блокировки.Contains(pair.Key) && pair.Value == null) .Select(pair => pair.Key)) { pairs.Insert(rand.Next(pairs.Count), (new KeyValuePair <ДатаГрафика, Наряд>(day, smen))); } } //Сортировка нарядов по длительности в порядке убывания pairs.Sort((pair, valuePair) => valuePair.Value.Длительность.CompareTo(pair.Value.Длительность)); аспределитьНаряды(pairs); //Выборка лучшего случая if (best == null) { best = ДатыГрафика.ToList(); if (Подразделения.Count == 0) { break; } bestres = Math.Abs(Подразделения.Max(dist => dist.ОтклонениеЗагруженности)) + Math.Abs(Подразделения.Min(dist => dist.ОтклонениеЗагруженности)); } else { var res = Math.Abs(Подразделения.Max(dist => dist.ОтклонениеЗагруженности)) + Math.Abs(Подразделения.Min(dist => dist.ОтклонениеЗагруженности)); if (res < bestres) { best.Clear(); best.AddRange(ДатыГрафика); ПересчитатьПодразделения(); bestres = res; } } } //ДатыГрафика = best; ДатыГрафика.Clear(); foreach (var date in best) { ДатыГрафика.Add(date); } аскидать(); }