蟻群算法解TSP(2)-核心代碼

引言

按照上一章的算法流程作煌,本章給出一個自己用Java代碼及面向?qū)ο笏悸穼崿F(xiàn)的蟻群算法清蚀。盡量追求代碼的質(zhì)量、可讀性和優(yōu)雅性揉忘,但也難免會有寫得不達標(biāo)的地方跳座,希望大家能去粗取精,獲取到對自己有益的部分即可泣矛。

道路類-Road

每條道路有它的距離和信息素濃度疲眷,所以需要抽象出一個這個Road類,勢必能為后續(xù)操作帶來很大便利~就像下面一樣:

class Road
{
    float distance; //距離
    float pheromone; //信息素 
    //構(gòu)造函數(shù)
    ......
}

城市類-City

為方便螞蟻k選出下一步要走的城市j您朽,我們還需建立一個City類狂丝,臨時存儲與螞蟻k當(dāng)前所處城市i相鄰的所有城市j的選擇概率、能見度與信息素濃度和(存儲該值是為方便后續(xù)計算所有相鄰城市的總和用)哗总。如下所示:

class NeighborCity 
{
    int id;
    float rate; //被選擇概率
    float vap; //能見度和信息素濃度總和
    
    //構(gòu)造函數(shù)
    ......
}

螞蟻類-Ant

為刻畫螞蟻尋徑過程中的各種行為几颜,如隨機化初始出生城市、選擇城市讯屈、到達城市等蛋哭,建立Ant類,如下所示:

class Ant 
{
    int[] passed;//已經(jīng)過的城市列表(禁忌表)
    float passedLength;//環(huán)游長度
    int curCity;//螞蟻當(dāng)前所在城市
    int curIndex;//下一城市需加入禁忌表的對應(yīng)位置
    
    //初始化螞蟻數(shù)據(jù)
    void init()
    {
        initPassed();
        passedLength=0.0f;
        curIndex=0;
        initBeginCity();
    }
    
    //初始化禁忌表
    void initPassed()
    {
        passed=new int[Constant.CITY_NUM+1];
        for(int i=0;i<passed.length;i++)
            passed[i]=Integer.MIN_VALUE;
    }
    
    //初始化螞蟻所在城市
    void initBeginCity()
    {
        Random rand=new Random();
        int beginCity=rand.nextInt(Constant.CITY_NUM);
        reachNextCity(beginCity);
    }
    
    //到達下一個城市
    void reachNextCity(int nextCity)
    {
        //累加周游距離
        passedLength += Constant.roads[curCity][nextCity].distance;
        
        //前進
        curCity=nextCity;
        passed[curIndex++]=nextCity+1;
    }
    
    //判斷城市nCity是否在禁忌表中
    boolean isPassedCity(int nCity)
    {
        for(int i=0;passed[i] != Integer.MIN_VALUE;i++)
        {
            if(passed[i] == nCity) //存在的城市
                return true;
        }
        return false;
    }
}

蟻群算法類-AntAlgorithm

該類對蟻群算法的各環(huán)節(jié)進行總控調(diào)度涮母,模擬螞蟻出生谆趾、螞蟻選擇路線、螞蟻環(huán)游叛本、信息素更新沪蓬、多輪環(huán)游等過程,具體實現(xiàn)如下:

class AntAlgorithm 
{    
    private Ant[] ants;//蟻群    
    float minLength = Float.MAX_VALUE;//當(dāng)前最短距離
    int[] minRoute; //當(dāng)前最短路線
    
    //構(gòu)造函數(shù)
    AntAlgorithm()
    {
        ants=new Ant[Constant.ANT_NUM];
        for(int i=0;i<Constant.ANT_NUM;i++)
            ants[i]=new Ant();
            
        minRoute=new int[Constant.CITY_NUM];
    }
    
    //算法流程開始
    void run()
    {
        for(int nc = 1; nc <= Constant.NC; nc++) //迭代次數(shù)
        {
            //初始化螞蟻數(shù)據(jù)
            for(int k = 0; k < Constant.ANT_NUM; k++)
                ants[k].init();
            
            //遍歷所有城市
            for(int look = 1; look < Constant.CITY_NUM; look++)
            {
                for(int k = 0; k < Constant.ANT_NUM; k++)//每只螞蟻
                {
                    int nextCity = select(ants[k]);//選擇下一個城市                    
                    ants[k].reachNextCity(nextCity);//到達下一個城市
                }
            }
    
            //返回起點城市并計算最優(yōu)路徑
            for(int k = 0; k < Constant.ANT_NUM; k++)//每只螞蟻
            {
                ants[k].reachNextCity(ants[k].passed[0]-1);
                if(minLength > ants[k].passedLength)
                {
                    minLength = ants[k].passedLength; //記錄最短距離
                    writeRoute(ants[k].passed); //記錄最短路線
                }
            }
            
            //對roads進行信息素更新
            for(int i = 0; i < Constant.CITY_NUM; i++)
            {
                for(int j = 0; j < Constant.CITY_NUM; j++)
                {
                    //所有路徑的信息素均蒸發(fā)
                    Constant.roads[i][j].pheromone *= Contant.p;
                    
                    for(int k = 0; k < Constant.ANT_NUM; k++)
                    {
                        for(int n = 0; n < Constant.CITY_NUM; n++)
                        {
                            int curCity = ants[k].passed[n]-1;
                            int nextCity = ants[k].passed[(n+1) % Constant.CITY_NUM]-1;
                            
                            if(curCity == i && nextCity == j)//出現(xiàn)過這段路徑
                            {
                                //更新路徑curCity,nextCity信息素
                                float dp = Constant.Q / ants[k].passedLength;//信息素增量
                                Constant.roads[i][j].pheromone += dp;    
                            }
                        }
                    }
                }
            }
        }    
    }
    
    //計算選擇概率+輪賭
    int select(Ant ant)
    {
        float totalVap = 0.0f;
        List<NeighborCity> neighborCityList = new LinkedList<NeighborCity>();
        NeighborCity neighborCity;
        for(int nextCity = 0; nextCity < Constant.CITY_NUM; nextCity++)
        {
            if(!ant.isPassedCity(nextCity+1))//可選擇城市
            {
                double pheromone = Constant.roads[ant.curCity][nextCity].pheromone;
                pheromone = Math.pow(pheromone, Constant.alpha);
                
                double visibility=1.0f / Constant.roads[ant.curCity][nextCity].distance;//能見度
                visibility=Math.pow(visibility, Constant.beta);
                
                float vap = (float) visibility + (float) pheromone;
                totalVap += vap; //累加VAP
                neighborCity = new NeighborCity(nextCity, vap);
                neighborCityList.add(neighborCity);//添加
            }
        }
        //計算每個城市被選中的概率
        ListIterator<NeighborCity> iterator = neighborCityList.listIterator(); //獲取迭代器
        while (iterator.hasNext())
        {
            neighborCity = iterator.next(); //取城市
            neighborCity.rate = neighborCity.vap / totalVap; //計算概率
        }
        
        //賭輪選擇其中一個城市
        float rate = (float) Math.random();
        iterator = neighborCityList.listIterator(); // 獲取迭代器
        while (iterator.hasNext())
        {
            neighborCity = iterator.next();
            if(rate <= neighborCity.rate)
                return neighborCity.id; //選擇該城市来候!
            else
                rate -= neighborCity.rate;
        }
        
        //概率精度所致跷叉,人為返回最后一個城市
        iterator = neighborCityList.listIterator();
        while (iterator.hasNext())
        {
            neighborCity = iterator.next();
            if(iterator.hasNext() == false) //選擇最后一個城市!
                return neighborCity.id;
        }
        
        return neighborCity.id;
    }
    
    //記錄最短路線
    void writeRoute(int[] route)
    {
        for(int i = 0; i < minRoute.length; i++)
            minRoute[i] = route[i];
    }
}

結(jié)語

核心代碼已經(jīng)貼完。下一章對蟻群算法所涉及的參數(shù)進行一些代碼上的說明营搅,并給出算法的實際運行結(jié)果云挟,同時與前面遺傳算法的運行結(jié)果進行對比分析。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末转质,一起剝皮案震驚了整個濱河市园欣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌峭拘,老刑警劉巖俊庇,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狮暑,死亡現(xiàn)場離奇詭異,居然都是意外死亡辉饱,警方通過查閱死者的電腦和手機搬男,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來彭沼,“玉大人缔逛,你說我怎么就攤上這事⌒栈螅” “怎么了褐奴?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長于毙。 經(jīng)常有香客問我敦冬,道長,這世上最難降的妖魔是什么唯沮? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任脖旱,我火速辦了婚禮,結(jié)果婚禮上介蛉,老公的妹妹穿的比我還像新娘萌庆。我一直安慰自己,他們只是感情好币旧,可當(dāng)我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布践险。 她就那樣靜靜地躺著,像睡著了一般吹菱。 火紅的嫁衣襯著肌膚如雪巍虫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天毁葱,我揣著相機與錄音垫言,去河邊找鬼贰剥。 笑死倾剿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚌成。 我是一名探鬼主播前痘,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼担忧!你這毒婦竟也來了芹缔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤瓶盛,失蹤者是張志新(化名)和其女友劉穎最欠,沒想到半個月后示罗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡芝硬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年蚜点,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拌阴。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡绍绘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迟赃,到底是詐尸還是另有隱情陪拘,我是刑警寧澤,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布纤壁,位于F島的核電站左刽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏酌媒。R本人自食惡果不足惜悠反,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望馍佑。 院中可真熱鬧斋否,春花似錦、人聲如沸拭荤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舅世。三九已至旦委,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間雏亚,已是汗流浹背缨硝。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留罢低,地道東北人查辩。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像网持,于是被迫代替她去往敵國和親宜岛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,747評論 2 361

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

  • 引言 蟻群算法差不多已經(jīng)水落石出了功舀,本章作為該系列的最后一章萍倡,再提一些小細(xì)節(jié)供大家參考。一方面是蟻群算法涉及的一些...
    阿堃堃堃堃閱讀 1,918評論 0 3
  • 旅行推銷員問題(Travelling salesman problem, TSP)是這樣一個問題:給定一系列城市和...
    treelake閱讀 15,353評論 0 36
  • 00:12 I study ants in the desert, in the tropical forest ...
    造物家英語閱讀 664評論 0 0
  • 這算是填3年前的一個坑吧辟汰,已經(jīng)懶癌晚期了列敲,想必也還是要掙扎下阱佛,那今天先從蟻群算法這個坑說起,如果你是要尋找怎么優(yōu)化...
    BreezeDust閱讀 2,182評論 1 26
  • 總是喜歡在閑暇之余戴而,光臨這樣的臨街咖啡?館瘫絮。隔著大大的落地窗,看窗外車水馬龍填硕。而自己麦萤,蜷縮在沙發(fā)里。聽著店內(nèi)飄散的...
    王的驛站閱讀 219評論 2 3