干貨|多起點(diǎn)的局部搜索算法(multi-start local search)解決TSP問題(附Java代碼及注釋)

以下文章作者向柯瑋

前言

各位看客老爺們瓜客,大家好~

今天要為大家?guī)淼?code>干貨是multi-start local search算法解決TSP問題(Java的實(shí)現(xiàn))俭正。

大家可不要因?yàn)檫@個(gè)算法的名字比較長(zhǎng),就覺得這個(gè)這個(gè)算法很難奸鬓,其實(shí)沒有哦-

這個(gè)算法還是非常簡(jiǎn)單的,希望大家能夠通過這個(gè)簡(jiǎn)單的算法來了解面對(duì)NP-hard問題掸读,我們可以采取的策略是什么串远。

算法簡(jiǎn)介

這個(gè)算法,其實(shí)大家通過名字就可以知道儿惫,一定和Iterated local search(迭代局部搜索算法)存在一定的聯(lián)系澡罚。

(這是當(dāng)然呀,名字都差不多肾请,還需要你說嗎留搔?)

迭代局部搜索算法公眾號(hào)在之前已經(jīng)介紹過了,有興趣的小伙伴可以再看看~

干貨|迭代局部搜索算法(Iterated local search)探幽(附C++代碼及注釋)

這兩個(gè)算法相似的地方我們就不多說了铛铁。我們主要介紹這個(gè)算法優(yōu)勢(shì)之處隔显。

優(yōu)勢(shì)

這種算法却妨,他是多起點(diǎn)的,初始解的生成和遺傳算法挺類似的括眠。

通過隨機(jī)打亂彪标,生成多個(gè)隨機(jī)新解,以此來增大達(dá)到最優(yōu)解的目的掷豺。

可能大家光這么看捞烟,沒啥感覺,我們可以通過數(shù)學(xué)公式來讓大家直觀的感受一下萌业。

我們認(rèn)為有N個(gè)城市坷襟,令傳統(tǒng)的LS搜索的次數(shù)為A,傳統(tǒng)的MLS搜索次數(shù)為A',改進(jìn)過的MLS搜索次數(shù)為A'',可以容易得出下面的公式生年。

現(xiàn)在讓我們?cè)賮砜纯磳?shí)際的程序跑出來的結(jié)果婴程。

這是傳統(tǒng)的LS。

這是傳統(tǒng)的MLS抱婉。

這是咱們優(yōu)化過的MLS档叔。

從以上兩個(gè)例子我們可以看出,MLS確實(shí)能夠提高單次程序運(yùn)行獲得優(yōu)質(zhì)解的概率蒸绩。

那么衙四,下面就讓我們簡(jiǎn)單地總結(jié)一下MLS的一些優(yōu)點(diǎn)。

  • 如果是在多線程情況下進(jìn)行探索患亿,那么速度和LS是差不多的
  • 探尋到最優(yōu)解的概率更大了
  • 對(duì)于新手來說传蹈,也可以更好的學(xué)習(xí)這種多個(gè)初始解的思想,便于以后GA等算法的學(xué)習(xí)

雖然本次代碼的展示仍然是采用單線程步藕,但是只要單線程的明白了惦界,多線程其實(shí)很容易就變過去了。

算法流程分析

現(xiàn)在我們先來介紹介紹最普遍的一種multi-start local search(多起點(diǎn)的局部搜索算法)咙冗。

大致的流程就是上面這副圖一樣沾歪,在讀取數(shù)據(jù)之后生成第一個(gè)解,即按照0-1-2-3……排序的解雾消。

然后將這個(gè)解進(jìn)行打亂灾搏,生成N組解,然后分別對(duì)這N組解利用2-opt算子進(jìn)行鄰域搜索立润。

我個(gè)人感覺這一種multi-start local search算法并不是很好狂窑。

  • 都是采用的多線程操作,對(duì)于新手都不是很友好桑腮,代碼不大看得明白
  • 算子太少蕾域,單一的2-opts算子很難找到較好的解
  • 對(duì)一些比較差的初始解(通過鄰域搜索都無法找到更好的解),沒有進(jìn)行一些處理

鑒于上面的不足,我對(duì)這個(gè)算法進(jìn)行了一定程度的改進(jìn)旨巷。如下圖巨缘。

代碼解析

在上面,我們大致的介紹了本次算法的大致實(shí)現(xiàn)過程采呐。

接下來若锁,我們對(duì)部分代碼進(jìn)行解讀

啟動(dòng)函數(shù)

這個(gè)函數(shù)是我們的main函數(shù),我們?cè)谶@里完成我們所有的操作斧吐。

我們?cè)趇ter函數(shù)中完成我們的搜索過程又固。

public class launch {
    public static void main(String[] args) {
        mls my_solution=new mls();                                      //生成mls對(duì)象
        readfile my_file=new readfile();                                //讀取文件
        my_file.buildInstance("F:\\mls\\data\\uy734.tsp.txt");          //讀取文件
        my_solution.setiLSInstance(my_file.getInstance());              //設(shè)置好距離矩陣
        my_solution.setsolution();                                      //設(shè)置好初始解
        my_solution.iter();                                             //開始迭代
        my_solution.print_best();                                       //輸出最優(yōu)解
        System.out.println("最佳適應(yīng)度為:"+my_solution.print_of());      //輸出最佳適應(yīng)度

    }
}

iter函數(shù)

這個(gè)函數(shù)就是最主要的函數(shù),相當(dāng)于整個(gè)搜索的過程的啟動(dòng)器煤率。

我們?cè)谶@個(gè)函數(shù)中仰冠,每次生成一個(gè)新的隨機(jī)解,然后進(jìn)行鄰域搜索蝶糯。這個(gè)就是區(qū)別于LS的根本之處洋只。

并用'tihuan'作為改隨機(jī)解是否為一個(gè)較好解的標(biāo)志。

 public void iter() {
        for(int c=0;c<this.iLSInstance.getN();c++)
        {
            Solution localsolution2 = this.currBest.clone();
            for (int j = c; j < this.iLSInstance.getN(); j++) {
                Solution now = ls(localsolution2.clone(), j);
                if (now.getOF() < this.dLSGlobalBest.getOF())
                    this.dLSGlobalBest = now.clone();
            }
        }
        for (int i = 0; i < this.iLSInstance.getN(); i++) {
            tihuan=false;
            Solution localsolution = this.currBest.clone();
            localsolution=restart(localsolution);
            for (int j = 0; j < this.iLSInstance.getN(); j++) {
                Solution now = ls(localsolution.clone(), j);
                if (now.getOF() < this.dLSGlobalBest.getOF())
                    this.dLSGlobalBest = now.clone();
            }
            for(int m=0;m<this.iLSInstance.getN()-1;m++)
                System.out.print(localsolution.getsolution().get(m)+"-->");
            System.out.println(localsolution.getsolution().get(this.iLSInstance.getN()-1));
            if(!tihuan)
                step++;
            if(step==50)
            {
                i--;
                step=0;
            }

        }
    }

LS函數(shù)

LS函數(shù)昼捍,即local search函數(shù)识虚,我們通過這個(gè)函數(shù),完成我們對(duì)每組解的每個(gè)位置的城市的鄰域搜索操作妒茬。

并用‘tihuan’作為是否生成更好的解(這里是指生成比當(dāng)前隨機(jī)解好的解)的標(biāo)志担锤。

image

public Solution ls(Solution ssolution,int i)  {
            Solution best = ssolution.clone();
        for (int j = i + 1; j < this.iLSInstance.getN() +i; j++) {
                Solution now=ssolution.clone();
                if(j<this.iLSInstance.getN()){
                now.swap(i, j);
                now.setOF(this.cLSCalculator.calc(this.iLSInstance, now));
                if (now.getOF() < best.getOF()) {
                    best = now.clone();
                    tihuan=true;
                }
                if(!tihuan){
                    now.swap(i,j);
                    now.relocate(i,j);
                    now.setOF(this.cLSCalculator.calc(this.iLSInstance, now));
                    if (now.getOF() < best.getOF()) {
                        best = now.clone();
                        tihuan=true;
                    }
                }
            }
                else if(j-this.iLSInstance.getN()<i){
                now.relocate(i,j-i);
                now.setOF(this.cLSCalculator.calc(this.iLSInstance, now));
                if (now.getOF() < best.getOF()) {
                    best = now.clone();
                    tihuan=true;
                    }
                }

        }
        return best;
    }

restart函數(shù)

這個(gè)是我們用來生成隨機(jī)新解的函數(shù)。

image
  public Solution restart(Solution solution){
        int[]haveset=new int[iLSInstance.getN()];
        haveset[0]=0;
        for(int i=0;i<iLSInstance.getN();i++){
            int n=rLSRandom.nextInt(iLSInstance.getN());
            while (haveset[n]!=0)
                n=rLSRandom.nextInt(iLSInstance.getN());
            solution.getsolution().set(i,n);
            haveset[n]=1;
        }
        solution.setOF(this.cLSCalculator.calc(this.iLSInstance, solution));
        return solution;
    }

小結(jié)

好了乍钻,我們現(xiàn)在把算法的大致流程肛循,主要的代碼都展示了一下,大家可以把自己的data輸進(jìn)去银择,看看結(jié)果怎么樣育拨,T^T,小瑋得到的結(jié)果都不是很理想--

該算法的隨機(jī)性很大欢摄,獲得優(yōu)質(zhì)解的難度還是蠻大的。

但是我覺得這個(gè)算法從傳統(tǒng)LS變過來給了我們很多啟發(fā)笋粟,比如說怀挠,在尋求最優(yōu)解的時(shí)候,我們可以采用多線程來提高尋求最優(yōu)解的效率等等害捕。

我希望大家通過本次推文绿淋,能夠了解到鄰域解是如何產(chǎn)生的,以及算法不夠好時(shí)的我們可以采用哪些改進(jìn)吞滞。

那么在下一次的推文中,會(huì)介紹一種船新的組合優(yōu)化解決VRPTW的算法~讓我們一起期待吧!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末殿漠,一起剝皮案震驚了整個(gè)濱河市佩捞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌一忱,老刑警劉巖莲蜘,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異帘营,居然都是意外死亡票渠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門芬迄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來问顷,“玉大人,你說我怎么就攤上這事薯鼠≡裾” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵出皇,是天一觀的道長(zhǎng)羞芍。 經(jīng)常有香客問我,道長(zhǎng)郊艘,這世上最難降的妖魔是什么荷科? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮纱注,結(jié)果婚禮上畏浆,老公的妹妹穿的比我還像新娘。我一直安慰自己狞贱,他們只是感情好刻获,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞎嬉,像睡著了一般蝎毡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上氧枣,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天沐兵,我揣著相機(jī)與錄音,去河邊找鬼便监。 笑死扎谎,一個(gè)胖子當(dāng)著我的面吹牛碳想,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播毁靶,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胧奔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了老充?” 一聲冷哼從身側(cè)響起葡盗,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啡浊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體巷嚣,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡廷粒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年坝茎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片思喊。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恨课,死狀恐怖剂公,靈堂內(nèi)的尸體忽然破棺而出吊宋,到底是詐尸還是另有隱情,我是刑警寧澤拖吼,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站因块,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拒名。R本人自食惡果不足惜芋酌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一脐帝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堵腹,春花似錦、人聲如沸旱易。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至浸船,卻和暖如春寝蹈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背箫老。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國打工耍鬓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留牲蜀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓在辆,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親匆篓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸦概,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容