Example #1
0
        //Вычисляем дельту весов и дельту цены по каждой парах  [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 с  сумой весов < вместимости рюкзака - не существует
        }