總時間限制: 1000ms 內存限制: 65536kBc++
某國家有n(1<=n<=10)座城市,給定任意兩座城市間距離(不超過1000的非負整數)。一個旅行商人但願訪問每座城市剛好一次(出發地任選,且最終無需返回出發地)。求最短的路徑長度。spa
第一行輸入一個整數n
接下來n行,每行n個數,用空格隔開,以鄰接矩陣形式給出城市間距離。該鄰接矩陣是對稱的,且對角線上全爲0code
一行,最短路徑的長度排序
6 0 16 1 10 12 15 16 0 10 2 10 8 1 10 0 10 5 10 10 2 10 0 9 3 12 10 5 9 0 8 15 8 10 3 8 0
19
這個問題能夠抽象爲在\(n\)階無向徹底圖\(K_n\)中,給定每一個邊加權(長度),而後在該帶權圖中求一條權和最小的哈密頓通路(只求解最小權和便可)。個人想法是使用深度優先搜索求解,過程當中使用了set來儲存通路的長度,因爲set使用二叉搜索樹,能夠在\(O(\log n)\)時間內完成元素插入,同時自動對元素排序,而且可以在\(O(1)\)時間內得到集合的最大和最小值,以略微節省運算時間。另外使用stack容器來臨時儲存全局變量sum(長度和)的值。遞歸
#include <bits/stdc++.h> using namespace std; int cities[12][12] = {}; bool visited[12] = {}; //標記去過的城市,若是去過了,則記true int n; int sum; set<int> path; stack<int> temp; void dfs(int start) { bool flag = true; for (int i = 1; i <= n; i++) if (!visited[i]) flag = false; if (flag) { path.insert(sum); return; } //設置邊界 //若是沒到遞歸邊界,繼續 for (int i = 1; i <= n; i++) { if (visited[i] == false) { visited[i] = true; if (sum > *path.begin() && path.size() != 0) { visited[i] = false; continue; } temp.push(sum); sum += cities[start][i]; dfs(i); sum = temp.top(); temp.pop(); visited[i] = false; } } } int main() { scanf("%d", &n); sum = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) scanf("%d", &cities[i][j]); for (int i = 1; i <= n; i++) dfs(i); printf("%d\n", *path.begin()); return 0; }
因爲此題中旅行商能夠從任意城市出發,我在解題的過程當中分別搜索了\(n\)個不一樣起點的解。但能夠看出,搜索的不一樣路徑中有大量重和部分,雖然對那些不可能成爲最優解的路徑進行了剪枝,搜索的效率仍然不高。
因而便有了另一種思路,即,在圖中先搜索出一條最短的哈密頓迴路,而後刪去這條迴路中的最長邊,便獲得一條哈密頓通路。由最短的哈密頓迴路獲得的這條哈密頓通路是不是最短的哈密頓迴路,我並無進行嚴格的證實。內存