目錄獲取實驗資料
實驗資料分析
總結參考資料
蠻力法也稱窮舉法或列舉法,是一種簡單直接地解決問題的方法,常常直接基於問題的描述,所以蠻力法也是最容易應用的方法。蠻力法所依賴的基本技術是遍歷,也稱掃瞄,即採用一定的策略依次理待求解問題的所有元素,從而找出問題的解。依次處理所有元素是蠻力法的關鍵,為了避免陷人重複試探,應保證處理過的元素不再被處理。
使用蠻力法求解 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次後,門鎖開著的,牢房中的犯人被放出,否則,犯人不得釋放。轉動門鎖的規則是這樣的,第一次通過牢房,從第一間開始轉動每一把鎖,...