回溯法是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯(其实回溯法就是对隐式图的深度优先搜索算法)。 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
哈密顿图是一个无向图,由天文学家哈密顿提出,由指定的起点前往指定的终点,途中经过所有其他节点且只经过一次。在图论中是指含有哈密顿回路的图,闭合的哈密顿路径称作哈密顿回路,含有图中所有顶点的路径称作哈密顿路径。
利用回溯法判断哈密顿回路是一种简单粗暴的试探,也因而容易理解,其方法如下代码,因注释详细,不再详述。
#include <iostream> using namespace std; const int MAX_V = 50; void print(int path[], int V) { cout << "存在哈密顿回路" << endl; for (int i = 0; i < V; i++) cout << path[i] << " "; cout << path[0] << endl; } //path记录路径,visited记录顶点是否访问过,len记录当前路径的长度 bool hamCycle(int graph[][MAX_V], int V, int path[], bool visited[], int current) { if (current == V) { //访问到最后一个顶点 if (graph[path[current - 1]][0] == 1) return true;//有到0点的边 else return false; } //遍历起点外其它顶点 for (int v = 1; v < V; v++) { //如果没访问过,并且有边相连 if (!visited[v] && graph[path[current - 1]][v] == 1) { visited[v] = true; path[current] = v; //当本次递归的child也为true时返回true if (hamCycle(graph, V, path, visited, current + 1)) return true; //当本条递归线路失败时恢复原图 path[current] = -1; visited[v] = false; } } return false; } //从起点开始引导 bool hamCycleStart(int graph[][MAX_V], int V) { int path[MAX_V]; memset(path, -1, sizeof(path)); bool visited[MAX_V] = { 0 }; path[0] = 0; visited[V] = true; //把起点标记为访问过 //起点已确定,current从1开始 if (hamCycle(graph, V, path, visited, 1) == false) { cout << "哈密顿回路不存在" << endl; return false; } print(path, V); return true; } int main() { int graph[MAX_V][MAX_V]; int V; cout << "请输入点的个数:" << endl; cin >> V; for (int i = 0;i < V;++i) { cout << "请输入图的第" << i << "行" << endl; for (int j = 0;j < V;++j) { cin >> graph[i][j]; } } hamCycleStart(graph, V); return 0; }