1. 程式人生 > >【算法】變鄰域搜索算法(Variable Neighborhood Search,VNS)超詳細一看

【算法】變鄰域搜索算法(Variable Neighborhood Search,VNS)超詳細一看

接受 優化問題 搜索 有關 str mat esc 重復 搜索算法

更多精彩盡在微信公眾號【程序猿聲】

技術分享圖片

變鄰域搜索算法(Variable Neighborhood Search,VNS)一看就懂的解析

00 目錄

  • 局部搜索再次科普
  • 變鄰域搜索
  • 造輪子寫代碼

01 局部搜索科普三連

雖然之前做的很多篇啟發式的算法都有跟大家提過局部搜索這個概念,為了加深大家的印象,在變鄰域主角登場之前還是給大家科普一下相關概念。熱熱身嘛~

1.1 局部搜索是什麽玩意兒?

官方一點:局部搜索是解決最優化問題的一種啟發式算法。對於某些計算起來非常復雜的最優化問題,比如各種NP完全問題,要找到最優解需要的時間隨問題規模呈指數增長,因此誕生了各種啟發式算法來退而求其次尋找次優解,是一種近似算法(Approximate algorithms),以時間換精度的思想。局部搜索就是其中的一種方法。

通俗一點:局部搜索算法是對一類算法的統稱,符合其框架的算法很多,比如之前公眾號推文中介紹的爬山法、模擬退火法和禁忌搜索算法都屬於局部搜索算法。盡管各個算法在優化過程中的細節存在差異,但在優化流程上呈現出很大的共性。

它的基本原理是在臨近解中叠代,使目標函數逐步優化,直至不能再優化為止。

1.2 局部搜索的過程

我們可以將局部搜索算法的統一框架描述為:

  1. 算法從一個或若幹個初始解出發。
  2. 在算法參數控制下由當前狀態的鄰域中產生若幹個候選解。
  3. 以某種策略在候選解中確定新的當前解。
  4. 伴隨控制參數的調節,重復執行上述搜索過程,直至滿足算法終止準則。
  5. 結束搜索過程並輸出優化結果。

1.3 局部搜索的幾大要素

局部搜索算法主要包含五大要素:

  1. 目標函數:用來判斷解的優劣。
  2. 鄰域的定義:根據不同問題,有著不同的鄰域定義。
  3. 初始解的產生規則
  4. 新解的產生和接受規則
  5. 算法終止準則

其中前兩個要素的定義和算法要解決的特定問題有關,而且不同的人對同一問題可能有完全不同的定義。後三個要素定義的不同則會產生各種不同的局部搜索算法,而它們的效率和最終解的質量也會有很大的差異。

02 變鄰域搜索算法

2.1 什麽是VNS?

對上面的局部搜索有一定的印象以後,理解變鄰域搜索也不難了。其實說白了,變鄰域搜索算法(VNS)就是一種改進型的局部搜索算法。它利用不同的動作構成的鄰域結構進行交替搜索,在集中性和疏散性之間達到很好的平衡。其思想可以概括為“變則通”。

變鄰域搜索依賴於以下事實:

  • 一個鄰域結構的局部最優解不一定是另一個鄰域結構的局部最優解。
  • 全局最優解是所有可能鄰域的局部最優解。

它由主要由以下兩個部分組成:

  • variable neighborhood descent (VND)
  • shaking procedure

大家別急,下面我們將會對這兩個部分進行分析。然後,before that……

2.2 你們一定想知道鄰域是什麽?

官方一點:所謂鄰域,簡單的說即是給定點附近其他點的集合。在距離空間中,鄰域一般被定義為以給定點為圓心的一個圓;而在組合優化問題中,鄰域一般定義為由給定轉化規則對給定的問題域上每結點進行轉化所得到的問題域上結點的集合。

通俗一點:鄰域就是指對當前解進行一個操作(這個操作可以稱之為鄰域動作)可以得到的所有解的集合。那麽鄰域的本質區別就在於鄰域動作的不同了。

2.3 還是要說說鄰域動作

鄰域動作是一個函數,通過這個函數,對當前解s,產生其相應的鄰居解集合。例如:對於一個bool型問題,其當前解為:s = 1001,當將鄰域動作定義為翻轉其中一個bit時,得到的鄰居解的集合N(s)={0001,1101,1011,1000},其中N(s) ∈ S。同理,當將鄰域動作定義為互換相鄰bit時,得到的鄰居解的集合N(s)={0101,1001,1010}。

2.4 variable neighborhood descent (VND)

VND其實就是一個算法框架,它的過程描述如下:

  1. 初始解S,定義M個鄰域,記為Nk(k = 1, 2, 3......m),i = 1。
  2. 使用鄰域結構Ni進行搜索,直到陷入局部最優解S′ 。
  3. 如果S′ 優於S,令S=S′,i=1; 否則,i++。
  4. 如果i≤m ,轉步驟2。
  5. 輸出最優解S。

我知道沒圖你們是不會點進來的……

VND的圖解如下:
技術分享圖片

只說兩點,再問自殺:

  • 當在本鄰域搜索找不出一個比當前解更優的解的時候,我們就跳到下一個鄰域繼續進行搜索。如圖中虛黑線所示。
  • 當在本鄰域搜索找到了一個比當前解更優的解的時候,我們就跳回第一個鄰域重新開始搜索。如圖中紅線所示。

之前我們把局部搜索比喻作爬山的過程,那麽每變換一次鄰域,也可以理解為切換了搜索的地形(landscape)。效果如下 :

技術分享圖片

每一次跳躍,得到都是一個新的世界……

偽代碼描述如下:

技術分享圖片

2.5 shaking procedure

其實呀,這玩意兒。說白了就是一個擾動算子,類似於鄰域動作的這麽一個東西。通過這個算子,可以產生不同的鄰居解。雖然名詞很多看起來很高大上,擾動、抖動、鄰域動作這幾個本質上還是沒有什麽區別的。都是通過一定的規則,將一個解變換到另一個解而已。這裏讀者還是抓其本質,不要被表象所迷惑了就好。

2.6 VNS過程

在綜合了前面這麽多的知識以後,VNS的過程其實非常簡單。可以描述為以下幾步:

  1. 產生初始解s1。
  2. shaking s1,得到解s2。
  3. 對解s2進行VND,得到解s3。
  4. 如果達到邊界條件,結束程序,輸出最優解。否則跳回第二步。

結合偽代碼,一目了然:

技術分享圖片

03 變鄰域搜索代碼應用舉例

分別舉兩個應用實例。

  • 變鄰域算法解決TSP問題
  • 變鄰域算法解決01背包問題

C++代碼。

欲獲取代碼,請關註我們的微信公眾號【程序猿聲】,在後臺回復:VNS代碼。即可獲取。

技術分享圖片

【算法】變鄰域搜索算法(Variable Neighborhood Search,VNS)超詳細一看