#include <stdio.h> #include <string> #include <iostream> #include <algorithm> #include <iterator> #include <cstdlib> #include <queue> #include "bb_algorithm.h" namespace bb { BranchBound::BranchBound(TspGraph& graph, std::vector<NodeType>& nodes_info) :m_graph(graph), m_nodes_info(nodes_info) { n = nodes_info.size(); } int BranchBound::process(std::vector<int>& result_list) {//最小费用分支定界代码,寻找最短旅行 //bestTour[1:n]存储最短旅行路径 std::priority_queue<HeapNode> liveNodeMinHeap; //costOfMinOutEdge[i]表示顶点i的最小出边 int *minCostOutEdge = new int[n + 1]; int sumOfMinCostOutEdges = 0; for (int i = 0; i < n; ++i) { int minCost = -1; for (int j = 0; j < n; ++j) if (m_graph[i][j] != -1 && (minCost == -1 || minCost > m_graph[i][j])) minCost = m_graph[i][j]; if (minCost == -1) return -1; minCostOutEdge[i] = minCost; sumOfMinCostOutEdges += minCost; } //初始E-节点的根 HeapNode eNode; eNode.lowerCost = sumOfMinCostOutEdges; eNode.currentCost = 0; eNode.restMinCost = sumOfMinCostOutEdges; eNode.s = 0; eNode.currentTour = new int[n]; //初始化排列为[1,2,3,...,n,1] for (int i = 0; i < n; ++i) eNode.currentTour[i] = i; int bestCostSoFar = -1; //当前最佳旅行耗费 int *currentTour = eNode.currentTour; //搜索排列树 while (eNode.s < n - 1) { currentTour = eNode.currentTour; if (eNode.s == n - 2) {//叶结点的父节点 //检查是否为当前最优旅行 if (m_graph[currentTour[n - 2]][currentTour[n - 1]] != -1 && m_graph[currentTour[n - 1]][0] != -1 && (bestCostSoFar == -1 || eNode.currentCost + m_graph[currentTour[n - 2]][currentTour[n - 1]] + m_graph[currentTour[n - 1]][0] < bestCostSoFar)) {//发现最优旅行,加入小根堆 bestCostSoFar = eNode.currentCost + m_graph[currentTour[n - 2]][currentTour[n - 1]] + m_graph[currentTour[n - 1]][0]; eNode.currentCost = bestCostSoFar; eNode.lowerCost = bestCostSoFar; eNode.s++; liveNodeMinHeap.push(eNode); } else { delete[] eNode.currentTour; //舍弃非最优的叶结点的父节点,释放内存 eNode.currentTour = nullptr; } } else {//生成子节点 for(int i = eNode.s + 1; i < n; ++i) if (m_graph[currentTour[eNode.s]][currentTour[i]] != -1) {//子节点可行 int currentCost = eNode.currentCost + m_graph[currentTour[eNode.s]][currentTour[i]]; int restMinCost = eNode.restMinCost - minCostOutEdge[currentTour[eNode.s]]; int leastCostPossible = currentCost + restMinCost; if (bestCostSoFar == -1 || leastCostPossible < bestCostSoFar) {//子树可能有更优的叶结点,把当前子树的根放入小根堆 HeapNode hNode; hNode.lowerCost = leastCostPossible; hNode.currentCost = currentCost; hNode.restMinCost = restMinCost; hNode.s = eNode.s + 1; hNode.currentTour = new int[n]; std::copy(currentTour, currentTour + n, hNode.currentTour); std::swap(hNode.currentTour[hNode.s], hNode.currentTour[i]); liveNodeMinHeap.push(hNode); } } //完成节点扩展,释放内存 delete[] eNode.currentTour; eNode.currentTour = nullptr; } if (liveNodeMinHeap.empty()) break; //取下一个E-节点 eNode = liveNodeMinHeap.top(); liveNodeMinHeap.pop(); } if (bestCostSoFar == -1) return -1; //复制到bestTour for (int i=0; i < n; i++) result_list.push_back(eNode.currentTour[i]); //释放小根堆中剩余元素的currentTour数组内存***虽然小根堆析构, //但是currentTour是new的内存,依然存在,故必须手动释放 while (true) { delete[] eNode.currentTour; if (liveNodeMinHeap.empty()) break; //取下一个E-节点 eNode = liveNodeMinHeap.top(); liveNodeMinHeap.pop(); } return bestCostSoFar; } }
#ifndef _BB_ALGORITHM_H_ #define _BB_ALGORITHM_H_ namespace bb { struct HeapNode { int lowerCost; //当前节点往后排列,整个回路所能取得的总耗费的下限 int currentCost; //从根到当前节点的当前排列的耗费 int restMinCost; //从当前节点到最后一个节点,每个节点的最小出边的耗费之和 int s; //从根节点到当前节点的路径为[0:s] int* currentTour; //从根节点到当前节点的路径(排列) //算术运算时的类型转换 operator int() { return lowerCost; } //重载大于号运算符,用于小根堆比较 bool operator<(const HeapNode &right) const { return lowerCost > right.lowerCost; } }; class BranchBound { public: BranchBound(TspGraph& graph, std::vector<NodeType>& nodes_info); int process(std::vector<int>& result_list); private: Graph& m_graph; std::vector<NodeType>& m_nodes_info; int n; }; } #endif
相关推荐
总之,分支定界法是一种强大且通用的求解优化问题的方法,特别适合解决像TSP这样具有大量可能解的组合优化问题。通过熟练掌握这一方法,我们不仅能解决旅行商问题,还能将其应用于其他类似的复杂优化问题。
【分支定界法详解】 分支定界法是一种用于求解整数规划问题的算法,尤其在处理混合整数规划问题时十分有效。该方法通过逐步分解问题空间并探索可能的解来找到最优解。在本例题中,我们面对的是一个多目标的投资决策...
分支定界法是一种搜索与迭代的方法,选择不同的分支变量和子问题进行分支。对于两个变量的整数规划问题,使用网格的方法有时更为简单。 [1] 通常,把全部可行解空间反复地分割为越来越小的子集,称为分支;并且对每...
最优化方法的整数规划的分支定界方法 整数线性规划的求解 求解整数规划的割平面法 整数规划的分支定界法
其中,分支定界法是一种常用的优化方法,用于解决混合整数规划问题。本文将详细介绍如何使用Matlab实现分支定界法解决混合整数规划问题。 Matlab实现分支定界法的基本思想 分支定界法是一种常用的优化方法,用于...
分支定界法(Branch and Bound,BNB)是一种在离散优化问题中寻找全局最优解的算法,尤其在解决整数规划和组合优化问题时非常有效。Matlab作为一种强大的数值计算和可视化工具,被广泛用于实现各种算法,包括分支定...
由于整数线性规划问题的求解难度较高,往往需要采用特殊的算法,其中“分支定界法”是一种有效的方法。 #### 分支定界法简介 分支定界法(Branch and Bound)是一种通过树状搜索策略来解决离散优化问题的方法。它...
分支定界法是一种全局优化策略,常用于解决整数规划问题。它通过将问题空间划分为子问题并逐步缩小搜索范围来寻找最优解。在TSP中,分支定界通常涉及创建一棵包含所有可能旅行路径的搜索树,并在每一步剪枝以排除不...
上述两个MATLAB函数提供了两种不同的方法来实现分支定界法求解整数线性规划问题。虽然第一个函数简单直观,但它可能在某些情况下表现不佳。相比之下,第二个函数更加灵活,可以处理更多类型的整数线性规划问题。在...
分支定界法是一种用于求解整数优化问题的有效算法,特别是在解决混合整数线性规划(MILP)问题时尤为常见。这种方法通过逐步限制可行域来搜索全局最优解,避免了陷入局部最优的情况。在MATLAB环境中实现分支定界法,...
分支定界法是解决整数规划问题的一种全局最优解搜索方法。它通过将问题的可行域分割成多个子集(分支),同时对每个子集进行下界(松弛问题的最优解)和上界(当前找到的最好解)的计算,逐步排除不可能包含最优解...
分支定界法是解决整数规划问题的一种经典算法,它通过不断细化搜索空间来寻找全局最优解。 分支定界法的基本思想是将问题的可行域(通常是连续的)逐步分解为一系列不相交的子集(即分支),然后对每个子集进行下界...
分支定界法是一种用于求解优化问题的有效方法,尤其在处理整数规划和组合优化问题时,如旅行商问题(Traveling Salesman Problem, TSP)。旅行商问题是一个经典的图论问题,目标是找到访问每个城市一次并返回起始...
3. **定界操作**:定界是分支定界法的核心,通过计算每个子区域的下界(通常是子问题的最优解的估计值)和上界(即子问题中目标函数的最大可能值),以排除不可能包含全局最优解的区域。一个.m文件可能会包含计算...
分支定界伪代码.txt
本主题将深入探讨如何使用MATLAB来实现三种主要的求解整数规划问题的方法:分支定界法、割平面法和隐式枚举法。 **分支定界法** 是一种全局优化技术,用于寻找整数或混合整数线性规划问题的全局最优解。该方法通过...
通过上述分析可以看出,使用MATLAB实现分支定界法解决整数线性规划问题是一种高效的方法。该方法不仅能够找到全局最优解,而且能够在计算资源有限的情况下有效地减少搜索空间。对于实际应用中的复杂优化问题,这种...
MATLAB分支定界法程序源码详解 MATLAB分支定界法程序源码是基于整数线性规划的算法,用于解决纯整数规划和混合整数规划问题。该算法的核心是通过递归调用自己的子函数来实现分支定界法的搜索过程。 函数定义 该...
分支定界法python实现,一个例子,可以供研究学习用