/// <summary> /// Test closest more than value threshold problem. /// </summary> public void TestCase2() { const double KNAPSACK_CAPACITY = 300; const int ITEM_NUM = 16; double[] weight = new double[ITEM_NUM] { 355, 367, 192, 100, 228, 456, 2714, 157, 151.9, 53, 98, 210, 111, 266, 276, 94 }; double[] price = new double[ITEM_NUM] { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 }; int i = 0; foreach (double w in weight) { if ((i++ % 4) == 0) { Console.Write("\n"); } Console.Write(" {0,7},", w.ToString("F2")); } List <Item> l = KnapsackSol.GenerateItems(weight, price); do { Console.WriteLine("\nPlease input a number as capacity ('Q' to quit):"); string str = Console.ReadLine(); double capacity; if (false == double.TryParse(str, out capacity)) { if (str.CompareTo("Q") == 0) { Console.WriteLine("You quit the program!"); break; } else { Console.WriteLine("Can't recognize the input number: {0}", str); continue; } } else { WeightNode wn = KnapsackSol.FindItemCollectionWithMostMatchValue(l, capacity); if (wn != null) { Console.WriteLine(wn.ToString()); } else { Console.WriteLine("No solution!"); } } } while (true); }
/// <summary> /// Test 0-1 knapsack problem with random values and weights. /// </summary> public void TestCase0() { const int TOTAL_ITEMS_NUM = 20; const double WEIGHT_MEAN = 4.0; const double VALUE_MEAN = 10.0; const double CAPACITY = 40.0; var v = KnapsackSol.GenerateGroceries(TOTAL_ITEMS_NUM, WEIGHT_MEAN, VALUE_MEAN, 1); WeightNode wn = KnapsackSol.Process(v, CAPACITY); Console.WriteLine(wn.ToString()); }
/// <summary> /// Test 0-1 knapsack problem with fixed values and weights. /// </summary> public void TestCase1() { const int ITEM_NUM = 10; const double KNAPSACK_CAPACITY = 30; double[] weight = new double[ITEM_NUM] { 1, 9, 3, 6, 5, 4, 7, 2, 8, 10 }; double[] price = new double[ITEM_NUM] { 2, 8, 9, 4, 7, 3, 1, 6, 5, 10 }; List <Item> l = KnapsackSol.GenerateItems(weight, price); WeightNode wn = KnapsackSol.Process(l, KNAPSACK_CAPACITY); Console.Write(wn.ToString()); }
public WeightNode(WeightNode node) { _Value = node._Value; _Weight = node._Weight; ItemsList.AddRange(node.ItemsList); }
/// <summary> /// Find the closest collection more than ValueThreshold. /// </summary> /// <param name="Items"></param> /// <param name="WeightThreshold"></param> /// <returns></returns> public static WeightNode FindItemCollectionWithMostMatchValue(IEnumerable <Item> Items, double WeightThreshold) { int i; int numOfMoreThanThreshold = 0; const int BEST_SOLUTION_NUM = 3; double maxWeight = 0.0; WeightNode dummy = new WeightNode() { _Value = 0.0, _Weight = 0.0 }; LinkedList <WeightNode> retList = new LinkedList <WeightNode>(); LinkedListNode <WeightNode> node = null; LinkedListNode <WeightNode> moreWeighNode = null; retList.AddLast(dummy); foreach (Item g in Items) { for (i = 0; i < g.Number; i++) { node = retList.Last; moreWeighNode = retList.Last; maxWeight = retList.Last.Value._Weight; while (node != null) { double totalWeight = node.Value._Weight + g.Weight; while (moreWeighNode != null) { if (Math.Abs(totalWeight - moreWeighNode.Value._Weight) < 0.001) { if (node.Value._Value + g.Value > moreWeighNode.Value._Value) { // employ the current node + the current grocery WeightNode wn = new WeightNode(node.Value); wn.AddItem(g); moreWeighNode.Value = wn; } break; } else if (totalWeight < moreWeighNode.Value._Weight) { moreWeighNode = moreWeighNode.Previous; } else if (totalWeight > moreWeighNode.Value._Weight) { if ((totalWeight < maxWeight) || (totalWeight < WeightThreshold) || ((totalWeight > WeightThreshold) && (numOfMoreThanThreshold < BEST_SOLUTION_NUM))) { WeightNode wn = new WeightNode(node.Value); wn.AddItem(g); retList.AddAfter(moreWeighNode, new LinkedListNode <WeightNode>(wn)); moreWeighNode = moreWeighNode.Next; if (totalWeight > WeightThreshold) { if (numOfMoreThanThreshold > BEST_SOLUTION_NUM) { retList.RemoveLast(); } else { numOfMoreThanThreshold++; } } maxWeight = retList.Last.Value._Weight; } break; } } node = node.Previous; } } } return(retList.First(o => (o._Weight >= WeightThreshold))); }
/// <summary> /// Select some grocery from Groceries and make sure /// 1. the total weight is less than MaxWeight /// 2. the total value is highest. /// /// </summary> /// <param name="Groceries"></param> /// <param name="MaxWeight"></param> /// <returns></returns> public static WeightNode Process(IEnumerable <Item> Groceries, double MaxWeight) { /* * (Value/Weight) * * retList * | * +- dummy (0.0/0.0) * | * +- WeightNode (V/W) --> Item0 -> Item1 -> ... -> ItemN * | * + ... * | * +- WeightNode (V/Capacity) -> Item0 -> Item1 -> ... ItemN * */ int i; WeightNode dummy = new WeightNode() { _Value = 0.0, _Weight = 0.0 }; LinkedList <WeightNode> retList = new LinkedList <WeightNode>(); LinkedListNode <WeightNode> node = null; LinkedListNode <WeightNode> moreWeighNode = null; retList.AddLast(dummy); foreach (Item g in Groceries) { for (i = 0; i < g.Number; i++) { node = retList.Last; moreWeighNode = retList.Last; while (node != null) { double totalWeight = node.Value._Weight + g.Weight; if (totalWeight <= MaxWeight) { while (moreWeighNode != null) { if (Math.Abs(totalWeight - moreWeighNode.Value._Weight) < 0.001) { if (node.Value._Value + g.Value > moreWeighNode.Value._Value) { // employ the current node + the current grocery WeightNode wn = new WeightNode(node.Value); wn.AddItem(g); moreWeighNode.Value = wn; } break; } else if (totalWeight < moreWeighNode.Value._Weight) { moreWeighNode = moreWeighNode.Previous; } else if (totalWeight > moreWeighNode.Value._Weight) { WeightNode wn = new WeightNode(node.Value); wn.AddItem(g); //moreWeighNode.AddGrocery(g); retList.AddAfter(moreWeighNode, new LinkedListNode <WeightNode>(wn)); moreWeighNode = moreWeighNode.Next; break; } } } node = node.Previous; } } } double maxValue = retList.Max(o => o._Value); return(retList.Last(o => (o._Value == maxValue))); }