回溯法是一種選優搜索法,又稱為試探法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。
在包含問題的所有解的解空間樹中,按照深度優先搜索的策略,從根結點出發深度探索解空間樹。當探索到某一結點時,要先判斷該結點是否包含問題的解,如果包含,就從該結點出發繼續探索下去,如果該結點不包含問題的解,則逐層向其祖先結點回溯(其實回溯法就是對隱式圖的深度優先搜索算法)。 若用回溯法求問題的所有解時,要回溯到根,且根結點的所有可行的子樹都要已被搜索遍才結束。 而若使用回溯法求任一個解時,只要搜索到問題的一個解就可以結束。
哈密頓圖是一個無向圖,由天文學家哈密頓提出,由指定的起點前往指定的終點,途中經過所有其他節點且只經過一次。在圖論中是指含有哈密頓回路的圖,閉合的哈密頓路徑稱作哈密頓回路,含有圖中所有頂點的路徑稱作哈密頓路徑。
利用回溯法判斷哈密頓回路是一種簡單粗暴的試探,也因而容易理解,其方法如下代碼,因注釋詳細,不再詳述。
#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; }