//Вычисляем дельту весов и дельту цены по каждой парах [ElementInGroup(i) - firstOutOfGroupElement], firstOutOfGroupElement - secondOutOfGroupElement //Выбираем мин дельту цены, такую что дельта весов > 0 (вес уменьшится); private GoodsPack CalcBestPackAlg(IOrderedEnumerable<Good> goodsByPrice, Good[] mostExpensiveGoods, Good firstOutOfGroupElement) { //Решаем переходить к следующему внегрупповому элементу или делать подстановку с целью уменьшения веса группы. //Для решения сравниваем выигрыш в весе группы, если //1) Заменим i-ый элемент, - всего n разниц //2) Перейдем к следующему элементу вне группы, = Вес (n+1) элемента - вес (n+2) элемента var currentOutOfGroupElement = firstOutOfGroupElement; currentOutOfGroupElement.Index = mostExpensiveGoods.Length; while (currentOutOfGroupElement != null) { foreach (var good in mostExpensiveGoods) { good.DeltaWeight = good.Weight - firstOutOfGroupElement.Weight; } var nextOutOfGroupElement = goodsByPrice.ElementAtSafe(currentOutOfGroupElement.Index + 1); if (nextOutOfGroupElement == null) { currentOutOfGroupElement.DeltaWeight = int.MinValue; } else { nextOutOfGroupElement.Index = currentOutOfGroupElement.Index + 1; } var allElements = new List<Good>(mostExpensiveGoods.Length + 1); allElements.AddRange(mostExpensiveGoods); allElements.Add(currentOutOfGroupElement); var maxDeltaWeight = allElements.Max(el => el.DeltaWeight); var mostPriorityByWeightElement = allElements.OrderByDescending(el => el.Price).First(e => e.DeltaWeight == maxDeltaWeight); if (mostPriorityByWeightElement.Index < mostExpensiveGoods.Length) {//значит нужно сделать ракировку элемента группы с элементом вне группы mostExpensiveGoods[mostPriorityByWeightElement.Index] = currentOutOfGroupElement; } if (mostExpensiveGoods.Sum(g => g.Price) <= _bagMaxWeight) {//Как только найдена группа с суммой элементов < вместимости рюкзака, группаз разрядности n считается найеденнной return CreatePack(mostExpensiveGoods); } currentOutOfGroupElement = nextOutOfGroupElement; } return new GoodsPack(); // групп ранга n с сумой весов < вместимости рюкзака - не существует }
private bool SubstituteElement(Good[] mostExpensiveGoods, Good outOfGroupElement) { //берем элемент вне группы с макс ценой, и пытаемся его вставить вместо каждого элемента группы (от меньш цены к большей), //если для всех комбинаций вес > вместимости рюкзаке, то группа не найдена (иначе группа найдена) for (int i = mostExpensiveGoods.Length - 1; i >= 0; i--) { var temp = mostExpensiveGoods[i]; mostExpensiveGoods[i] = outOfGroupElement; if (mostExpensiveGoods.Sum(g => g.Weight) <= _bagMaxWeight) { return true; } mostExpensiveGoods[i] = temp; } return false; }