蠻力法解 TSP 問題

2022-03-08 21:26:01 字數 3735 閱讀 1593

目錄獲取實驗資料

實驗資料分析

總結參考資料

蠻力法也稱窮舉法或列舉法,是一種簡單直接地解決問題的方法,常常直接基於問題的描述,所以蠻力法也是最容易應用的方法。蠻力法所依賴的基本技術是遍歷,也稱掃瞄,即採用一定的策略依次理待求解問題的所有元素,從而找出問題的解。依次處理所有元素是蠻力法的關鍵,為了避免陷人重複試探,應保證處理過的元素不再被處理。

使用蠻力法求解 tsp 問題的思想是,通過窮舉的方式把所有可能的路徑找出來,然後對每一條路徑都計算開銷,最終找出開銷最小的路徑。例如對於如圖 4 個城市的拓撲,使用蠻力法求解的過程如**所示。

序號路徑

路徑長度

是否最短

1a->b->c->d->a18否

2a->b->d->c->a11是

3a->c->b->d->a23否

4a->c->d->b->a11是

5a->d->b->c->a23否

6a->d->c->b->a18否

當城市規模增大時,存在的路徑數會呈現指數型增長,例如 11 個城市的拓撲圖如下所示。

tsp 是個 np 完全問題,我們需要圖結構來進行儲存。我選擇鄰接矩陣儲存城市拓撲圖,定義的圖結構體如下。

typedef struct    //圖的定義

mgraph;

接下來就需要把城市拓撲儲存在鄰接矩陣中,因為城市拓撲是完全圖,因此我們需要儲存所有城市之間的距離。

mgraph createmgraph(int num)    //建圖 

} for (int i = 1; i <= num; i++) }

topography.n = num;

return topography;

}

想要獲取最短的路線,使用蠻力法進行分析時需要先獲取所有的路徑。dfs 可以獲取所有的路徑,編寫的**如下。注意當獲取一條新路徑時,需要先把該路徑拷貝到下乙個路徑,因為遞迴實現的 dfs 無法返回上一層遞迴執行填充操作。這麼做是可行的,因為相鄰路徑不需要回溯的路線是一樣的,而回溯的部分會直接覆蓋原來的路線。

void dfs(int new_point, int cities_visited, int &path_index)    //深度遍歷 

path_index++;

} else

}} return;

}

接下來要計算所有路徑的長度,並且得出最短的路線。同時我們也需要確定 dfs 執行了多少次,方便我們分析時間複雜度。

int main()

//初始化訪問狀態

for(int i = 1; i <= topography.n; i++)

//出發

cout << "從哪個城市出發:";

cin >> start_point;

visited[start_point] = 1;

//獲取所有路徑

dfs(start_point, cities_visited, path_index);

//得出最短路徑

ofstream outfile;

outfile.open("11.txt");

for (int i = 1; i < path_index; i++)

if(sum < min_sum)

}cout << "\n最短路徑為路徑" << min_path << ":";

for (int j = 1; j <= cities_num; j++)

cout << path[min_path][cities_num + 1] << endl;

cout << "最短路徑長度為:" << min_sum << endl;

cout << "dfs 次數為:" << count;

return 0;

}

使用上述不同規模的城市拓撲分析tsp問題,得出的實驗資料如下。

城市規模(個)

路線數(條)

dfs次數(次)

資料檔案大小(kb)46

當使用蠻力法解決tsp問題時,需要考慮從某個城市出發的所有路線。由於城市之間彼此互通,城市拓撲是個完全圖,因此所有路線的數量規模是 n-1 個城市的全排列。

當輸入城市數量n時,會產生n!條路線,從而計算路徑長度的操作就需要執行n!次。也就是說蠻力法解決tsp 問題的 t(n) = n!,從而得出 o(n) = n!。無論是路線數、dfs 次數還是資料檔案大小,都能明顯地體現這個趨勢。

我一開始使用的是 c++ 的 new 運算子動態記憶體分配二維陣列。但是除了城市規模 4 的資料下,其他的規模均無法正常執行,並且主函式 「return value 3221225477」。經過查閱資料得知這可能和未初始化的變數或指標引發的,但是我並不知道問題**及其原因,無奈之下只好直接定義了乙個較大的二維陣列進行儲存。

在測試城市規模 12 的資料時,由於棧區空間已經用盡,我打算使用動態記憶體分配使用堆區記憶體。結果需要分配的記憶體過多,導致所有記憶體空間全部被 c++ 占用,而 c++ 並沒有智慧型保護記憶體的機制,導致我的電腦直接宕機。在強行斷電並修復電腦之後覺定放棄 12 個城市的 tsp 問題求解。

蠻力法是解決問題明確而直接的手法,程式編寫較為簡單,思路是模擬情景下的所有可能性進行分析,在時間允許下是極佳的演算法。但是在不同的情景下會存在效率低下的情況,我們會需要更加巧妙的演算法提高解決問題的效率,期待接下來對演算法的進一步學習,使用其他的演算法對這些問題進行求解。

《資料結構(c語言版|第二版)》—— 嚴蔚敏 李冬梅 吳偉民 編著,人民郵電出版社

《演算法設計與分析(第二版)》——王紅梅,胡明 編著,清華大學出版社

graphviz 安裝並使用 (python)

c++檔案和流

蠻力法 獄吏問題

某國王大赦囚犯,讓一獄吏n次通過一排鎖著的n間牢房,每通過一次,按所定規則轉動n間牢房的某些門鎖,每轉動一次,原來鎖著的門被開啟,原來開啟的門被鎖上,通過n次後,門開著的,牢房中的犯人放出,否則犯人不得釋放。轉動門鎖的規則是這樣的,第一次通過牢房,從第1間開始要轉動每一把門鎖,即把全部的鎖開啟 第2...

分治法 蠻力法 金塊問題

乙個老闆有 n 塊金塊,他要把最重的一塊獎勵給最優秀的員工,最輕的一塊獎勵給次優秀的員工。假設有一台比較重量的儀器,希望用最少的比較次數找出最重和最輕的金塊。題意就是在一堆亂序元素中找到兩個最值元素 最大值 最小值 本題解法思路有兩種 分治法 蠻力法 分治演算法實現上,又可以分兩種思路 遞迴 非遞迴...

蠻力法求解「獄吏問題」

問題描述 獄吏問題 某國王對囚犯進行大赦,讓一獄吏n次通過一排鎖著的n間牢房,每通過一次按所定規則轉動n間牢房中的某些門鎖,每轉動一次原來鎖著的被開啟,原來開啟的被 鎖上通過n次後,門鎖開著的,牢房中的犯人被放出,否則,犯人不得釋放。轉動門鎖的規則是這樣的,第一次通過牢房,從第一間開始轉動每一把鎖,...