爬山法、分支限界法求解哈密顿环问题

最后更新于:2022-04-01 20:31:31

问题描述: (1)哈密顿环问题:输入是一个无向连通图G=(V,E);如果G中存在哈密顿环则输出该环。 (2)最小哈密顿环问题:输入是一个无向连通图G=(V,E),每个节点都没有到自身的边,每对节点间都有一条非负加权边;输出一个权值代价和最小的哈密顿环。注意:事实上输入图是一个完全图,因此哈密顿环是一定存在的。 实现哈密顿环搜索算法 (1)哈密顿环问题:(a)实现基于树的基本搜索算法(BFS,DFS) (b)爬山法 (2)最小哈密顿环问题:(a)实现求解最小哈密顿环问题的分支界限算法。 1.DFS 算法的主要步骤: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_57187d6e7351c.jpg) 2.BFS 算法的主要步骤: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_57187d6e933e7.jpg) 3.ClimbingHill 算法的主要步骤: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_57187d6eadff0.jpg) 4.BranchBound 算法的主要原理: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_57187d6ec7b59.jpg) 源码: Grap.h ~~~ /* *Tree Search Strategy 15S103182 Ethan *2015.12.1 */ #include #include #include #include #include #include using namespace std; template //E为图中边的权值的数据类型 class Graph { private: int maxVertices; //图中最大顶点数 E **matrix;//邻接矩阵 public: E maxWeight; //代表无穷大的值 Graph(int sz);//创建SZ大小的基于邻接矩阵的图 ~Graph();//析构函数 int NumberOfVertices() { return maxVertices; //返回最大顶点数 } E getWeight(int v1, int v2); //取边(v1,v2)上的权值 int getFirstNeighbor(int v);//取顶点v的第一个邻接顶点 int getNextNeighbor(int v, int w);//取顶点v的邻接顶点W的下一个邻接顶点 int Init(istream &in);//根据用户输入,获得图的邻接矩阵 int RandInitN();//随机初始化图(无向图) int RandInit();//随机初始化图(完全无向图) int output(ostream &out); //输出图的矩阵到文件 int output(); //输出图的矩阵到控制台 }; template Graph::Graph(int sz) { //创建SZ大小的基于邻接矩阵的图 maxWeight = std::numeric_limits::max(); maxVertices = sz; matrix = new E *[sz]; for (int i = 0; i Graph::~Graph() { for (int i = 0; i E Graph::getWeight(int v1, int v2) { //取边(v1,v2)上的权值 if (v1 >= 0 && v1= 0 && v2 int Graph::getFirstNeighbor(int v) { //取顶点v的第一个邻接顶点 if (!(v >= 0 && v int Graph::getNextNeighbor(int v, int w) { //取顶点v的邻接顶点W的下一个邻接顶点 if (!(v >= 0 && v= 0 && w int Graph::Init(istream &fin) { //根据输入文件,获得图的邻接矩阵 int v1, v2; E edge; while (fin >> v1 >> v2 >> edge) { if (v1 >= 0 && v1= 0 && v2 int Graph::RandInitN() { //随机初始化图(无向图,非完全) for (int i = 0; i int Graph::RandInit() { //随机初始化图(无向完全图) for (int i = 0; i int Graph::output(ostream &out) { //输出图的矩阵 for (int i = 0; i int Graph::output() { //输出图的矩阵 for (int i = 0; i #include #include #include #include #include #include #include using namespace std; template struct NODE { int dep; //表示该结点在搜索树的第几层 int *vertices; //该节点包含的各个顶点 E length; //从根到当前结点已经走过的路径长度 NODE(int depth) { dep = depth; vertices = new int[dep]; }; void cpy(int *&des) { for (int i = 0; i int dfs(int start, Graph &myGraph) { //deepFirst 判断图中是否存在哈密顿回路 stack myStack; myStack.push(start); int numVertices = myGraph.NumberOfVertices(); bool *visited = new bool[numVertices]; memset(visited, false, numVertices); int v; int w = -1; while (!myStack.empty()) { //栈不为空 v = myStack.top(); visited[v] = true; if (w == -1) { w = myGraph.getFirstNeighbor(v); } else { w = myGraph.getNextNeighbor(v, w); } for (; w != -1 && visited[w] == true; w = myGraph.getNextNeighbor(v, w)) {} if (w == -1) { //未找到可行的下一个顶点,子节点都在栈中 myStack.pop(); //回溯 w = v; visited[v] = false; } else { //找到可行的下一个顶点 myStack.push(w); //放入栈中 if (myStack.size() == numVertices) { //走过所有的顶点 if (myGraph.getWeight(start, w) == std::numeric_limits::max()) { //判断最后一个顶点有没有回到起点的边 myStack.pop(); visited[w] = false; } else { //成功找到回路 return 1; } } else { w = -1; } } } return 0; } template int ch(int start, Graph &myGraph) { //climbingHill 爬山法判断图中是否存在哈密顿回路 stack myStack; myStack.push(start); int numVertices = myGraph.NumberOfVertices(); bool *visited = new bool[numVertices]; memset(visited, false, numVertices); int v; int w = -1; while (!myStack.empty()) { //栈不为空 v = myStack.top(); visited[v] = true; if (w == -1) { w = myGraph.getFirstNeighbor(v); } else { w = myGraph.getNextNeighbor(v, w); } for (; w != -1 && visited[w] == true; w = myGraph.getNextNeighbor(v, w)) {} int greedy = w;//贪心选择子顶点 for (; w != -1 && visited[w] == false; w = myGraph.getNextNeighbor(v, w)) { if(myGraph.getWeight(v, w) < myGraph.getWeight(v, greedy)) { greedy = w; } } w = greedy; if (w == -1) { //未找到可行的下一个顶点 myStack.pop(); //回溯 w = v; visited[v] = false; } else { //找到可行的下一个顶点 myStack.push(w); //放入栈中 if (myStack.size() == numVertices) { //走过所有的顶点 if (myGraph.getWeight(start, w) == std::numeric_limits::max()) { //判断最后一个顶点有没有回到起点的边 myStack.pop(); visited[w] = false; } else { //成功找到回路 return 1; } } else { w = -1; } } } return 0; } template int climbingHill(int start, Graph &myGraph, ostream & fout) { //算法解决图的最小哈密顿回路问题 v为回路的起点和终点 stack myStack; myStack.push(start); int numVertices = myGraph.NumberOfVertices(); bool *visited = new bool[numVertices]; memset(visited, false, numVertices); int v; int w = -1; while (!myStack.empty()) { //栈不为空 v = myStack.top(); visited[v] = true; if (w == -1) { w = myGraph.getFirstNeighbor(v); } else { w = myGraph.getNextNeighbor(v, w); } for (; w != -1 && visited[w] == true; w = myGraph.getNextNeighbor(v, w)) {} int greedy = w;//贪心选择子顶点 for (; w != -1 && visited[w] == false; w = myGraph.getNextNeighbor(v, w)) { if(myGraph.getWeight(v, w) < myGraph.getWeight(v, greedy)) { greedy = w; } } w = greedy; if (w == -1) { //未找到可行的下一个顶点 myStack.pop(); //回溯 w = v; visited[v] = false; } else { //找到可行的下一个顶点 myStack.push(w); //放入栈中 if (myStack.size() == numVertices) { //走过所有的顶点 if (myGraph.getWeight(start, w) == std::numeric_limits::max()) { //判断最后一个顶点有没有回到起点的边 myStack.pop(); visited[w] = false; } else { //成功找到回路 stack temp; while (!myStack.empty()) { int n = myStack.top(); temp.push(n); myStack.pop(); } fout << "哈密顿回路 : "; E distance = 0; int n = temp.top(); myStack.push(n); temp.pop(); int last = n; fout << n << "--"; while (!temp.empty()) { n = temp.top(); myStack.push(n); temp.pop(); distance += myGraph.getWeight(last, n); last = n; fout << n << "--"; } fout << start << endl; distance += myGraph.getWeight(last, start); fout << "总长度为:" << distance << endl; return distance; } } else { w = -1; } } } return std::numeric_limits::max(); } template int bfs(int start, Graph & myGraph) { //broadFirst 判断图中是否存在哈密顿回路 stack > myStack; //队列 int s = myGraph.getFirstNeighbor(start); for (s = myGraph.getNextNeighbor(start, s); s != -1; s = myGraph.getNextNeighbor(start, s)) { NODE n(2); n.vertices[0] = start; n.vertices[1] = s; n.length = myGraph.getWeight(start, s); myStack.push(n); } while (!myStack.empty()) { //队列不为空 NODE n = myStack.top(); myStack.pop(); int v = n.vertices[n.dep - 1]; if (n.dep + 1 == myGraph.NumberOfVertices()) { //到了最后一层 判断是不是哈密顿回路 int w; for (w = myGraph.getFirstNeighbor(v); w != -1; w = myGraph.getNextNeighbor(v, w)) { if (n.find(w) == false) break; } if (w != -1) { if (myGraph.getWeight(w, start)::max()) { return 1; } } } for (int w = myGraph.getFirstNeighbor(v); w != -1; w = myGraph.getNextNeighbor(v, w)) { if (n.find(w) == false) { NODE ne(n.dep + 1); ne.length = n.length + myGraph.getWeight(v, w); n.cpy(ne.vertices); ne.vertices[ne.dep - 1] = w; myStack.push(ne); } } } return 0; } //分支限界法求解最短哈密顿回路问题 template int branchBound(int start, Graph & myGraph, ostream & fout) { stack > myStack; //队列 E minDistance = climbingHill(start,myGraph,fout);//爬山法获取首界限 int s = start; for (s = myGraph.getFirstNeighbor(start); s != -1; s = myGraph.getNextNeighbor(start, s)) {//首次分支 NODE n(2); n.vertices[0] = start; n.vertices[1] = s; n.length = myGraph.getWeight(start, s); myStack.push(n); } while (!myStack.empty()) { //队列不为空 NODE n = myStack.top(); myStack.pop(); int v = n.vertices[n.dep - 1]; if (n.dep + 1 == myGraph.NumberOfVertices()) { //到了最后一层 判断是不是哈密顿回路 int w; for (w = myGraph.getFirstNeighbor(v); w != -1; w = myGraph.getNextNeighbor(v, w)) { if (n.find(w) == false)//确定最后一个节点 break; } if (w != -1) { if (myGraph.getWeight(w, start)::max()) { //如果找到且存在路径 E tempDistance = n.length + myGraph.getWeight(v, w) + myGraph.getWeight(w, start); if (minDistance>tempDistance) { // 形成回路 fout << "哈密顿回路为:"; // cout << "哈密顿回路为:"; for (int i = 0; i ne(n.dep + 1); ne.length = n.length + myGraph.getWeight(v, w); if (ne.length myGraph(i); Graph myGraphN(i); myGraph.RandInit();//随机初始化完全无向图 myGraphN.RandInitN();//随机初始化图 int a = clock(); cout<<"deepFirst:"< myGraphN(4); // ifstream fin("input.txt"); // myGraphN.Init(fin); // cout<<"deepFirst:"< ';