public void Calc(Good[] goods) { _goods = goods; _matrix = new int[_maxWeight + 1, _goodsCount]; //Реализуем массив функции //Реализуем алгоритм Беллмана for (int weight = 1; weight <= _maxWeight; weight++) // Загружаем рюкзак если его вместимость = Weight for (int i = 1; i < _goodsCount; i++) // берем предметы с 1 по goodsCount //если вес предмета больше Weight, или предыдущий набор лучше выбираемого if (goods[i].Weight > weight) { _matrix[weight, i] = _matrix[weight, i - 1]; //тогда берем предыдущий набор goods[i].IsTaken = false; } else if (_matrix[weight, i - 1] >= (_matrix[weight - goods[i].Weight, i - 1] + goods[i].Price)) { _matrix[weight, i] = _matrix[weight, i - 1]; //тогда берем предыдущий набор goods[i].IsTaken = false; } else { _matrix[weight, i] = _matrix[weight - goods[i].Weight, i - 1] + goods[i].Price; //иначе добавляем к предыдущему набору текущий предмет goods[i].IsTaken = true; } }
public void PrintGoods(Good[] goods) { var sb = new StringBuilder(); foreach (var good in goods) { sb.AppendFormat("{0}:{1}{2}", good.Price, good.Weight, "|"); } Console.Write(sb.ToString(0, sb.Length - 1)); }
public void Calc(Good[] goods) { var groupsCapacity = GetGroupsCapacity(goods); //сортируем товары по убыванию цены var goodsByPrice = goods.OrderByDescending(g => g.Price); Dictionary<int, GoodsPack> bestPacks = new Dictionary<int, GoodsPack>(); //идем от мин-групп к маскимальным for (int groupRang = groupsCapacity.MinElementsCount; groupRang <= groupsCapacity.MaxElementsCount; groupRang++) { //берем n элементов с макс ценами (n - вместимость группы) Good[] mostExpensiveGoods = goodsByPrice.Take(groupRang).ToArray(); //считаем веса, если общий вес > вместимости рюкзака, решаем какой элемент нужно откинуть из группы (иначе оптимальная группа найдена) if (mostExpensiveGoods.Sum(g => g.Weight) <= _bagMaxWeight) { GoodsPack bestPack = CreatePack(mostExpensiveGoods); bestPacks.Add(groupRang, bestPack); continue; } //алгоритм выбора элемента для замены: var firstOutOfGroupElement = goodsByPrice.ElementAtSafe(groupRang); if (firstOutOfGroupElement == null) { bestPacks.Add(groupRang, new GoodsPack()); continue; } if (SubstituteElement(mostExpensiveGoods, firstOutOfGroupElement)) { GoodsPack bestPack = CreatePack(mostExpensiveGoods); bestPacks.Add(groupRang, bestPack); continue; } GoodsPack pack = CalcBestPackAlg(goodsByPrice, mostExpensiveGoods, firstOutOfGroupElement); bestPacks.Add(groupRang, pack); //Увеличиваем разрядность анализируемой группы } var packs = bestPacks.Values; var maxPackPrice = packs.Max(p => p.Price); BestPriceGoodsPack = packs.First(p => p.Price == maxPackPrice); }
//Вычисляем дельту весов и дельту цены по каждой парах [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; }
/// <summary> /// Посчитать группы какой вместимости возможны на переданном наборе элементов /// </summary> /// <param name="goods"></param> /// <returns></returns> private GroupsCapacity GetGroupsCapacity(Good[] goods) { //Отсортировать товары по весам //найти мин кол-во элементов в группе и максимальное кол-во элементов var goodsByWeightAsc = goods.OrderBy(g => g.Weight); int totalWeight = 0; var enumerator = goodsByWeightAsc.GetEnumerator(); //calc max elements count GroupsCapacity capacity = new GroupsCapacity(); //calc max elements count while (enumerator.MoveNext()) { if (totalWeight + enumerator.Current.Weight > _bagMaxWeight) { break; } totalWeight += enumerator.Current.Weight; capacity.MaxElementsCount++; } var goodsByWeightDesc = goodsByWeightAsc.Reverse(); enumerator = goodsByWeightDesc.GetEnumerator(); //calc min elements count totalWeight = 0; while (enumerator.MoveNext()) { if (totalWeight + enumerator.Current.Weight > _bagMaxWeight) { break; } totalWeight += enumerator.Current.Weight; capacity.MinElementsCount++; } return capacity; }
public void Calc(Good[] goods) { int price; List<Good> bag = new List<Good>(); // это рюкзак List<string> goodNames = new List<string>(); // буфер id List<string> prices = new List<string>(); // список цен коллекций Random random = new Random(); Good good; int weightTotal = 0; int priceTotal = 0; string idLine = ""; int errorCount = 0; startLoop: bag.Clear(); nextAdd: // добавление предметов в рюкзак в разном порядке good = goods[random.Next(0, Convert.ToInt32(goods.Length))]; if (!bag.Contains(good)) bag.Add(good); else goto nextAdd; weightTotal = 0; // проверка общего веса foreach (Good item in bag) { weightTotal += item.Weight; } if (weightTotal < _bagMaxWeight) goto nextAdd; else { for (int i = 0; ; i++) { if (weightTotal <= _bagMaxWeight) break; else { bag.RemoveAt(Convert.ToInt32(bag.Count - 1)); // проверка общего веса weightTotal = 0; foreach (Good item in bag) { weightTotal += item.Weight; } } } } goodNames.Clear(); priceTotal = 0; // подсчет общей цены коллекции foreach (Good item in bag) { price = item.Price; goodNames.Add(item.Name); priceTotal += price; } // сбор id в строку idLine = ""; int count = 0; foreach (string i in goodNames) { if (count != (goodNames.Count - 1)) idLine += i + ","; else idLine += i; count++; } if (!prices.Contains(Convert.ToString(priceTotal) + ";" + idLine)) { var pack = new GoodsPack(); pack.AddRange(bag); _goodsPacks.Add(pack); prices.Add(Convert.ToString(priceTotal) + ";" + idLine); } else { errorCount++; if (errorCount >= ((goods.Length) * (goods.Length))) goto countingPrice; } goto startLoop; countingPrice: var maximumPrice = _goodsPacks.Max(p => p.Price); BestPriceGoodsPack = _goodsPacks.First(p => p.Price == maximumPrice); BestPriceGoodsPack.SetTaken(); }
private static Good[] Create3GoodsArray() { var goods = new Good[3]; for (int i = 0; i < 3; i++) { string name = (i + 1).ToString(); goods[i] = new Good(name); } goods[0].Weight = 20; goods[0].Price = 60; goods[1].Weight = 30; goods[1].Price = 90; goods[2].Weight = 50; goods[2].Price = 100; return goods; }
private static Good[] Create9GoodsArray() { var goods = new Good[9]; for (int i = 0; i < 9; i++) { string name = (i + 1).ToString(); goods[i] = new Good(name); } goods[0].Weight = 36; goods[0].Price = 68; goods[1].Weight = 18; goods[1].Price = 10; goods[2].Weight = 19; goods[2].Price = 50; goods[3].Weight = 23; goods[3].Price = 20; goods[4].Weight = 29; goods[4].Price = 65; goods[5].Weight = 32; goods[5].Price = 30; goods[6].Weight = 35; goods[6].Price = 60; goods[7].Weight = 44; goods[7].Price = 40; goods[8].Weight = 67; goods[8].Price = 70; return goods; }
static void MainBellmanAlg(string[] args) { int i, j; //просто переменные :) Console.WriteLine("Данная программа поможет Вам заполнить Ваш рюкзак максимально ценными товарами\nАвтор: Владимир Рыбалка"); //Введем количество товаров do { incorrEnter = false; Console.Write("\nКакое количество товаров вы рассматриваете для приобретения: "); try { _goodsCount = Convert.ToInt32(Console.ReadLine()); } catch (FormatException) { incorrEnter = true; _goodsCount = 0; } } while (incorrEnter); var goods = new Good[_goodsCount]; //Создаем массив заданного размера //Создадим объекты товаров for (i = 0, j = i + 1; i < goods.Length; i++, j++) { Console.Write("\n\nВведите название " + j + "-го товара: "); _enteredName = Console.ReadLine(); do { incorrEnter = false; Console.Write("Введите вес товара: "); try { _enteredWeight = Convert.ToInt32(Console.ReadLine()); } catch (FormatException) { incorrEnter = true; _enteredWeight = 0; } } while (incorrEnter); do { incorrEnter = false; Console.Write("Введите цену товара: "); try { _enteredPrice = Convert.ToInt32(Console.ReadLine()); } catch (FormatException) { incorrEnter = true; _enteredPrice = 0; } } while (incorrEnter); var good = new Good(_enteredName); //Создаем объект good.Weight = _enteredWeight; good.Price = _enteredPrice; goods[i] = good; } // Введем размер рюкзака do { incorrEnter = false; Console.Write("\nВведите размер вашего рюкзака (контейнера): "); try { _bagMaxWeight = Convert.ToInt32(Console.ReadLine()); } catch (FormatException) { incorrEnter = true; _bagMaxWeight = 0; } } while (incorrEnter); BellmanAlg alg = new BellmanAlg(_bagMaxWeight, _goodsCount); alg.Calc(goods); Print(goods, alg.BestPriceGoodsPack.Price); Console.ReadKey(); }
// Метод выводит на экран рюкзак static void Print(Good[] goods, int maxPriceForGoodsPack) { Console.WriteLine("\nМаксимальная стоимость: " + maxPriceForGoodsPack); Console.Write("Взяты следующие предметы: "); foreach (Good good in goods) if (good.IsTaken) Console.Write(good.Name + " "); }