1. 程式人生 > >演算法筆記 //11_旅行售貨員問題

演算法筆記 //11_旅行售貨員問題

問題重述:

   售貨員要到若干城市去推銷商品,已知各城市之間的路程(或旅費)。他要選定一條從駐地出發,經過每個城市一次,最後回到駐地的路線,使總的路程(或總旅費)最小。
   路線是一個帶權圖。圖中各邊的費用(權)為正數。圖的一條周遊路線是包括V中的每個頂點在內的一條迴路。周遊路線的費用是這條路線上所有邊的費用之和。
   旅行售貨員問題的解空間可以組織成一棵樹,從樹的根結點到任一葉結點的路徑定義了圖的一條周遊路線。旅行售貨員問題要在圖G中找出費用最小的周遊路線。
   設有p個城市,假設每兩個城市之間都有直通通道,兩個城市之間的路程已知,一個售貨員要到每個城市推銷產品,然後返回原出發地,問這個售貨員應該如何選擇路線,能使每個城市都經過一次且僅一次,並且行程最短,這就是著名的旅行售貨員問題,也即貨郎擔問題。

演算法思想:

   用圖論的術語來描述旅行售貨員問題:即在一個正權完全圖中尋找一個具有最小權的哈密頓迴路,對於此問題,由於完全圖中必然存在哈密頓迴路,那麼目前可以用於求解的方法有列舉法,分枝限界法,這兩種演算法可以求得此問題的精確解,但到目前為止,還沒有求解這一問題的有效演算法,我們可以利用分支限界法,回溯法求解此問題的近似解,以求得與最優解最為接近的解。
   我們根據圖的圖生成了一棵2叉排列樹,這樣求最小路程就轉換為如何解這棵空間樹的問題。我們做過生成排列的題目如果我們窮舉一遍,那麼自然可以得到我們想要的解,但是這樣時間複雜度O(n!),效率低得可憐,所以我們只有來優化他。
   首先我們可以用一個記錄的方法,用bestc存放當前已經得到的最優解,那麼只要我得到當前的解已經超過最優解了,那麼剩下的我就可以不用算了;其次:如果對於任意兩個城市是無邊標記的(即兩個城市之間是沒有通路的)也不用考慮這個我們做了優化,具體的時間複雜度只能根據問題的規模而定了,接下來就是實現的問題了。(PS:這道題目還可以用記憶搜尋,也就是搜尋+DP,可以進一步提高效率,不過這裡沒有實現,轉自百度文庫)

C++ 程式碼如下:

#include<iostream>
using namespace std;

const int NoEdge=-1;
const int MAX=20;
int G[MAX][MAX];    // 用來存放所有的兩個地點之間的距離
int ans[MAX],x[MAX];
int bestc,cc;       // 存放當前已經得到的最優解

void init(int n)    // 初始化、讀取使用者輸入值函式
{
    int i,j,len;
    memset(G,NoEdge,sizeof(G));     
    // memset是一個 C++ 函式:將 s 所指向的某一塊記憶體中的前 n 個位元組的內容全部設
// 置為 ch 指定的ASCII值, 第一個值為指定的記憶體地址,塊的大小由第三個引數指定, // 這個函式通常為新申請的記憶體做初始化工作, 其返回值為指向s的指標。 // 作用是在一段記憶體塊中填充某個給定的值,它是對較大的結構體或陣列進行清零操作 // 的一種最快方法。(因為主函式中要迴圈輸入,所以在這裡不可省略。額。。。應該如此) cout << "Please input the distance of every two cities(such as '1 2 54',that means you'll spend 54 arrving at city 2 from city 1. And the distance of the final two cities should be expressed like '0 0'.): " << endl; while(cin >> i >> j) // 地點用數字編號來表示 { if(i==0 && j==0) break; // 若輸入的是同一個地點,中止程式,也就是最後輸入 0 0 後,會輸出結果 cin >> len; // 讀取某兩個地點之間的距離 G[i][j]=len; // 儲存這個距離 G[j][i]=len; // 城市一到城市二的距離和反過來是一樣的 } for(i=1; i<=n; i++) { x[i]=i; } bestc = 0x3f3f3f3f; // 將最優值初始化為無窮大 cc = 0; } void Swap(int& i,int& j) // 交換 i、j 的值 { int t = i; i = j; j = t; } void Traveling(int i,int n) // 計算函式,i 在主函式中初始化為 2 { int j; if( i == n+1 ) // 也就是說 2 == n + 1,即使用者只輸入了一個城市 { if(G[ x[n-1] ][ x[n] ] != NoEdge && G[ x[n] ][ 1 ] != NoEdge && (cc + G[ x[n] ][ 1 ] < bestc ) ) { for(j=1; j<=n; j++) { ans[j] = x[j]; } bestc = cc + G[ x[n] ][ 1 ]; } } else { for(j=i; j<=n; j++) { if( G[ x[i-1] ][ x[j] ] != NoEdge && ( cc + G[ x[i-1] ][ x[j] ] < bestc) ) { Swap( x[i],x[j] ); cc += G[ x[i-1] ][ x[i] ]; Traveling(i+1,n); cc -= G[ x[i-1] ][ x[i] ]; Swap( x[i],x[j] ); } } } } void print(int n) // 輸出列印結果函式 { cout << "The idearest value is: " << bestc << endl; cout << "The idearest routine is: "; for(int i=1; i<=n; i++) { cout << ans[i] <<" -> "; } cout << ans[1] << endl; } int main() { int n; while(1) { cout << "Please input the number of cities: "; cin >> n; init(n); Traveling(2,n); print(n); cout << "---------------------------------------------------------------------" << endl; } return 1; }

這裡寫圖片描述

相關推薦

演算法筆記 //11_旅行售貨員問題

問題重述: 售貨員要到若干城市去推銷商品,已知各城市之間的路程(或旅費)。他要選定一條從駐地出發,經過每個城市一次,最後回到駐地的路線,使總的路程(或總旅費)最小。 路線是一個帶權圖。圖中各邊的費用(權)為正數。圖的一條周遊路線是包括V中的每個頂點

演算法旅行售貨員問題

問題描述:售貨員要到n個城市去推銷商品,已知各城市之間的路程(代價)a[][],試選擇一條路,從第一個城市出發經過每個城市一遍,最後回到出發城市所耗費的代價最小。例: 問題分析:分析可知解空間是一棵排列樹,每一條從根節點到達葉子結點的路徑代表了n個頂點的一種排列。定義x[N]記錄可行解。剪枝函式:

演算法java實現--回溯法--旅行售貨員問題--排列樹

旅行售貨員問題的java實現(回溯法--排列樹) 具體問題描述以及C/C++實現參見網址 http://blog.csdn.net/liufeng_king/article/details/8890603 /** * 旅行售貨員問題--回溯法 * @author

演算法學習1:旅行售貨員問題

      有一推銷員,欲到n <=10個城市推銷產品。為了節省旅行費用,在出發前他查清了任意兩個城市間的旅行費用,想找到一條旅行路線,僅經過每個城市一次,最終回到出發原點,使旅行費用最少。本問題已知城市n,和n*n的表達任意兩個城市間費用的矩陣。求最短路徑及其費用。

演算法設計與分析: 3-15 雙調旅行售貨員問題

3-15 雙調旅行售貨員問題 問題描述 歐氏旅行售貨員問題是對給定的平面上 n 個點確定一條連線這 n 個點的長度最短的哈密 頓迴路。由於歐氏距離滿足三角不等式,所以歐氏旅行售貨員問題是一個特殊的具有三角不 等式性質的旅行售貨員問題。它仍是一個 NP

回溯法----旅行售貨員問題java演算法

我的java演算法: import java.util.Arrays; /** * Created by Administrator on 2018/4/21. */ public class CityTravel { static int ci

演算法5.旅行售貨員問題和數獨遊戲。

某售貨員要到4個城市去推銷商品,已知各城市之間的路程,如右圖所示。請問他應該如何選定一條從城市1出發,經過每個城市一遍,最後回到城市1的路線,使得總的周遊路程最小?並分析所設計演算法的計算時間複雜度。 (1) 演算法設計思路 解向量:{1,2,3,4,

《機器學習實戰》第二章——k-近鄰演算法——筆記

在看這一章的書之前,在網上跟著博主Jack-Cui的部落格學習過,非常推薦。 部落格地址:http://blog.csdn.net/c406495762  《Python3《機器學習實戰》學習筆記(一):k-近鄰演算法(史詩級乾貨長文)》 講述的非常細緻,文字幽默有趣,演算法細

九章演算法筆記 5.深度優先搜尋 Depth First Search

DFS cs3k.com 什麼時候用dfs? 短, 小, 最問題 而90%DFS的題, 要麼是排列, 要麼是組合 組合搜尋問題 Combination 問題模型:求出所有滿足條件的“組合” 判斷條件:組合中的元素是順序無關的 時間複雜度:與 2^n 相關 遞迴三要素 一般來說,如果面試官不特

九章演算法筆記 4.寬度優先搜尋 Breadth First Search

演算法與題型 cs3k.com DFS: 用於搜尋, 題目中有ALL字樣 二分法: 用於時間複雜度小於O(n)的情況 分治法: 二叉樹問題, 子問題和父問題有關係 BFS:- 二叉樹上的寬搜- 圖上的寬搜: 拓撲排序- 棋盤上的寬搜   什麼時候應該用BFS? 圖

九章演算法筆記 3.二叉樹與分治演算法Binary Tree & Divide Conquer

大綱 cs3k.com • 時間複雜度訓練 II • 二叉樹的遍歷演算法 Traverse in Binary Tree Preorder / Inorder / Postorder • 二叉樹的深度優先搜尋 DFS in Binary Tree 1.遍歷問題 Preorder

九章演算法筆記 2.Binary Search

大綱 cs3k.com 第一境界 二分法模板 • 時間複雜度小練習• 遞迴與非遞迴的權衡• 二分的三大痛點• 通用的二分法模板 第二境界 • 二分位置 之 圈圈叉叉 Binary Search on Index – OOXX• 找到滿足某個條件的第一個位置或者最後一個位置 第三境界 •二分位置 之

九章演算法筆記 1.Introducing Algorithm Interview & Coding Style

Implement strStr cs3k.com http://www.lintcode.com/problem/strstr/ Returns the position of the first occurrence of string target in string source, or -1

九章演算法筆記 8.雜湊表與堆 Hash & Heap

大綱 cs3k.com 資料結構概述 雜湊表 Hash: a.原理  b.應用 堆 Heap: a.原理    b.應用-優先佇列 Priority Queue  c.替代品-TreeMap   資料結構的兩類問題 cs3k

九章演算法筆記 6.連結串列與陣列 Linked List & Array

刷題注意事項 cs3k.com 每道題需要總結的 思路 演算法 核心程式碼 這個題得到的啟示!!!重點是bug free的能力   linked list理解 結果兩個都是 1 2 3 node是存在main函式裡的區域性變數, 還是全域性變數? 區

九章演算法筆記 7.兩根指標 Two Pointers

大綱 cs3k.com 同向雙指標 相向雙指標 Two Sum :3.1 大小• = target• <= target • > target     3.2 去重• unique pairs    3.3 離得近• closest to t

演算法筆記-快速冪

快速冪就是快速的求底數的整數次方,比起樸素的方法O(n)的時間複雜度,其時間複雜度是O(log2n)。這是很不錯的一個效率提升。 通常要求一個數X的Y次方,記做X^Y,樸素的計算方法是把X乘Y次得到這個結果。 而快速冪計算的過程是,對於指數Y進行奇偶性的判斷。為了方便解釋,

演算法筆記—日期類

  題目連結:http://codeup.cn/problem.php?cid=100000578&pid=3 題目描述 編寫一個日期類,要求按xxxx-xx-xx 的格式輸出日期,實現加一天的操作。 輸入 輸入第一行表示測試用例的個數m,接下來m

演算法筆記 — 列印日期

題目連結:http://codeup.cn/problem.php?cid=100000578&pid=2 題目描述 給出年分m和一年中的第n天,算出第n天是幾月幾號。 輸入 輸入包括兩個整數y(1<=y<=3000),n(1<=n<=366)。

演算法筆記》總結一

      目錄 第二章 1. 定義變數時儘可能賦初值,避免在程式時出現未知訪問錯誤!!!(不能想當然的賴編譯器的預設初始化) 1.1C程式的記憶體佈局。 1.2記憶體管理的目的及建議 1.3 note that 2. ASCII碼的程式設計