/// <summary>
        /// 开始解决问题
        /// </summary>
        /// <param name="testdata">要解决的问题的描述字符串</param>
        public override void Solve(string testdata)
        {
            if (this.UIReference == null)
            {
                throw new Exception("问题解决器尚未初始化就被使用");
            }
            // 算法开始
            this.BeginTimeStamp = DateTime.Now;
            // 分析测试数据字符串
            this.testData = testdata;
            string[] lineitem = this.testData.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            this.Capacity = Convert.ToInt32(lineitem[0]);
            // 读取背包大小和物品种类数
            this.ItemTypeCount = Convert.ToInt32(lineitem[1]);
            this.Items         = new List <PackageItem>();
            // 读取每种物品的属性
            for (int i = 2; i < lineitem.Length; i++)
            {
                var aLine = lineitem[i].Split('\t');
                var aW    = Convert.ToInt32(aLine[1]);
                var aV    = Convert.ToInt32(aLine[2]);
                this.Items.Add(new PackageItem((i - 2).ToString(), aW, aV));
            }
            // 对单位价值做排序
            this.Items.Sort((x, y) =>
            {
                if (x.UnitValue > y.UnitValue)
                {
                    return(-1);
                }
                else if (x.UnitValue < y.UnitValue)
                {
                    return(1);
                }
                else
                {
                    return(0);
                }
            });
            // 初始化算法
            this.currentMaxBound     = 0;
            this.currentBestValue    = 0;
            this.candidateRouterNode = null;
            BBNode recursiveNode = new BBNode(-1, null);

            // 调用回溯函数,开始递归求解
            this.BackTrace(0, recursiveNode);
            // 反算路径
            this.GetSolutionRouter();
            // 算法结束
            this.EndTimeStamp = DateTime.Now;
        }
示例#2
0
        /// <summary>
        /// 分支界限求最大价值路径
        /// </summary>
        /// <returns>能够达到的最大价值</returns>
        private void BranchAndBound()
        {
            int    itemId            = 0;
            double currentUpperBound = this.GetMaxBound(itemId);

            this.heapQueue = new PriorityQueue <BBNode>();
            BBNode currentExpandNode = null;

            // 分支界限搜索
            while (true)
            {
                // 左子树(放入)可以拓展
                double LeftWeight = this.currentWeight + this.Items[itemId].Weight;
                if (LeftWeight <= this.Capacity)
                {
                    if (this.currentValue + this.Items[itemId].Value > this.currentBestValue)
                    {
                        this.currentBestValue           = this.currentValue + this.Items[itemId].Value;
                        this.CandidateRouterDestination = this.InsertToHeap(currentUpperBound,
                                                                            this.currentValue + this.Items[itemId].Value, this.currentWeight + this.Items[itemId].Weight,
                                                                            itemId + 1, true, currentExpandNode);
                    }
                    else
                    {
                        this.InsertToHeap(currentUpperBound, this.currentValue + this.Items[itemId].Value,
                                          this.currentWeight + this.Items[itemId].Weight, itemId + 1, true, currentExpandNode);
                    }
                }
                currentUpperBound = this.GetMaxBound(itemId + 1);
                // 右子树的价值上界比当前最大值还大才有拓展的意义
                if (currentUpperBound >= this.currentBestValue)
                {
                    this.CandidateRouterDestination = this.InsertToHeap(currentUpperBound,
                                                                        this.currentValue, this.currentWeight, itemId + 1, false, currentExpandNode);
                }
                // 所有节点都已经展开就返回
                if (this.heapQueue.Empty())
                {
                    return;
                }
                // 取下一个要生长的节点
                currentExpandNode = this.heapQueue.Top();
                this.heapQueue.Pop();
                this.currentWeight = currentExpandNode.AccWeight;
                this.currentValue  = currentExpandNode.AccValue;
                currentUpperBound  = currentExpandNode.ValueUpperBound;
                itemId             = currentExpandNode.Level;
            }
        }
示例#3
0
        /// <summary>
        /// 将一个新的活结点插入到子集树和最大堆heap中
        /// </summary>
        /// <param name="maxValue">价值上界</param>
        /// <param name="accValue">节点累积价值</param>
        /// <param name="accWeight">节点累积质量</param>
        /// <param name="level">节点层次</param>
        /// <param name="pickFlag">是否挑选当前物品</param>
        /// <param name="parent">上层节点</param>
        /// <returns>加入的节点</returns>
        private BBNode InsertToHeap(double maxValue, double accValue, double accWeight, int level, bool pickFlag, BBNode parent)
        {
            BBNode node = new BBNode(level, null);

            node.ValueUpperBound = maxValue;
            node.AccValue        = accValue;
            node.AccWeight       = accWeight;
            node.Pick            = pickFlag;
            node.Parent          = parent;
            if (level <= this.ItemTypeCount)
            {
                this.heapQueue.Push(node);
            }
            return(node);
        }
        /// <summary>
        /// 求子树的价值上界
        /// </summary>
        /// <param name="itemId">当前考虑的物品</param>
        /// <returns>最大上界</returns>
        private double GetValueBound(int itemId, BBNode currentNode)
        {
            double space     = this.Capacity - currentNode.AccWeight;
            double maxborder = currentNode.AccValue;

            // 要放入的所有物品应该比当前剩余空间还要小
            while (itemId < this.ItemTypeCount && this.Items[itemId].Weight <= space)
            {
                space     -= this.Items[itemId].Weight;
                maxborder += this.Items[itemId].Value;
                itemId++;
            }
            // 装填剩余容量装满背包
            if (itemId < this.ItemTypeCount)
            {
                maxborder += ((double)this.Items[itemId].Value / (double)this.Items[itemId].Weight) * space;
            }
            return(maxborder);
        }
 /// <summary>
 /// 回溯法搜索问题最优解
 /// </summary>
 /// <param name="depth">当前递归的深度</param>
 /// <param name="parent">搜索树上层节点</param>
 private void BackTrace(int depth, BBNode parent)
 {
     // 递归边界
     if (depth >= this.ItemTypeCount)
     {
         // 优于局部最小值时替换她
         if (this.candidateRouterNode == null ||
             parent.AccValue > this.candidateRouterNode.AccValue)
         {
             this.currentBestValue    = parent.AccValue;
             this.candidateRouterNode = parent;
         }
         return;
     }
     // 计算价值上界
     this.currentMaxBound = this.GetValueBound(depth, parent);
     // 如果下一物体可以放入就尝试放入
     if (parent.AccWeight + this.Items[depth].Weight <= this.Capacity)
     {
         // 放入
         BBNode leftNode = new BBNode(depth, parent);
         leftNode.Pick      = true;
         leftNode.AccValue  = parent.AccValue + this.Items[depth].Value;
         leftNode.AccWeight = parent.AccWeight + this.Items[depth].Weight;
         // 递归
         this.BackTrace(depth + 1, leftNode);
     }
     // 不放入当前物品的情况
     this.currentMaxBound = this.GetValueBound(depth + 1, parent);
     if (this.currentMaxBound >= this.currentBestValue)
     {
         BBNode rightNode = new BBNode(depth, parent);
         rightNode.AccValue  = parent.AccValue;
         rightNode.AccWeight = parent.AccWeight;
         this.BackTrace(depth + 1, rightNode);
     }
 }