遺傳演算法解TSP問題的C++源碼

來源:互聯網
上載者:User

《智能最佳化演算法》課的一次作業。報著學點東西的態度,沒有從網上下載(網上好像都是那個VC6的MFC程式),純C++,從零寫起,順便學習了一下如何用STL。

 

#include <iostream><br />#include <iomanip><br />#include <vector><br />#include <iterator><br />#include <algorithm><br />#include <fstream><br />#include <math.h><br />#include <time.h></p><p>const int NCITY = 51;<br />struct CityCoor<br />{<br />int sn, x, y;<br />};<br />struct Sequence<br />{<br />double distance;<br />std::vector<int> vSeqnc;<br />};</p><p>std::vector<CityCoor> vCityCoors(NCITY);<br />std::vector<std::vector<double>> vDistanceMatrix(NCITY);</p><p>double computDistance( const std::vector<int>& v );</p><p>namespace ga<br />{<br />const int POPSIZE = NCITY*5;<br />const int GENERATION = 5000;//在變化顯著的情況下為5000代<br />const int SIMILAR_TIMES = 200;<br />const double DIFF = 1e-15;//量化變化不顯著<br />const double P_CROSSOVER = 0.3;//交叉機率<br />const double P_MUTATION = 0.1;//變異機率<br />int nGen = 0;</p><p>std::vector<int> vCitySequence(NCITY);<br />std::vector<Sequence> vChromsome(POPSIZE+1);//第一個染色體只記錄上一代遺傳的最優解而不參與遺傳運算<br />std::vector<double> vProbability(POPSIZE+1);</p><p>namespace itor<br />{<br />inline void printSequence(int sn) {std::cout << sn << " ";}<br />inline void printCityCoors(const CityCoor& cc) {std::cout << cc.sn << " " << cc.x << " " << cc.y << "/n";}<br />inline void printChromsome(const Sequence &s) {std::cout << s.distance << " ";}</p><p>inline void itorDistance( Sequence& se ) {se.distance = computDistance(se.vSeqnc);}<br />inline void initChromsome(Sequence& v);</p><p>inline void testPrintSeqLen(const Sequence &s) {std::cout << s.vSeqnc.size() << " ";}<br />}//itor::<br />inline bool less_second(const Sequence &a, const Sequence &b) {return a.distance < b.distance;}<br />}//ga::</p><p>//////////////////////////////////////////////////////////////////////////<br />//迭代器<br />typedef std::vector<CityCoor>::iterator vitorCityCoor;<br />typedef std::vector<int>::iterator vitorSn;</p><p>typedef std::vector<int>::size_type vintSize;</p><p>typedef std::vector<CityCoor>::const_iterator cvitorCityCoor;<br />typedef std::vector<int>::const_iterator cvitorSn;<br />typedef std::vector<Sequence>::const_iterator cvitorChromsome;</p><p>//////////////////////////////////////////////////////////////////////////<br />std::vector<Sequence> vTemp(ga::POPSIZE+1);</p><p>//////////////////////////////////////////////////////////////////////////<br />//全域函數,具體作用可見Definition<br />bool readTSP_Data();<br />inline double myrand(double, double);<br />void crossover();<br />void mutation();<br />void selection();<br />void calcDistanceMatrix();</p><p>bool isValid(std::vector<int> v)<br />{<br />sort(v.begin(), v.end());</p><p>for (std::vector<int>::size_type i=0; i<v.size()-1; ++i)<br />if (v[i] == v[i+1])<br />{<br />std::cout << "序列出錯!!!!!!!!!/n";<br />std::cout << "v[" << i << "]" << "=v[" << i+1 << "]/n";<br />for_each(v.begin(), v.end(), ga::itor::printSequence);<br />system("pause");<br />return false;<br />}<br />std::cout << "序列正確/n";<br />return true;<br />}</p><p>int main()<br />{<br />//////////////////////////////////////////////////////////////////////////<br />std::cout<<"#讀入資料";<br />if (!readTSP_Data())<br />{<br />std::cerr << "---讀入城市座標出錯!";<br />exit(1);<br />}<br />std::cout<<" OK/n";<br />clock_t startTime = clock();</p><p>std::cout<<"#計算城市距離矩陣";<br />calcDistanceMatrix();<br />std::cout<<" OK/n";</p><p>//求適應函數<br />ga::vProbability[0] = 0.05;<br />double a = 0.05;<br />for (int i=1; i<=ga::POPSIZE; ++i)<br />{<br />a *= 0.95;<br />ga::vProbability[i] = ga::vProbability[i-1] + a;<br />}<br />//////////////////////////////////////////////////////////////////////////<br />std::cout<<"#初始化" << ga::POPSIZE << "個染色體:";<br />for_each(ga::vChromsome.begin()+1, ga::vChromsome.end(), ga::itor::initChromsome);<br />std::cout<<" OK/n";</p><p>ga::vChromsome[0] = ga::vChromsome[1];<br />//先淘汰一次,以最佳化初值<br />sort(ga::vChromsome.begin()+1, ga::vChromsome.end(), ga::less_second);</p><p>//////////////////////////////////////////////////////////////////////////<br />std::cout<<"/n#開始遺傳演算法,結束條件為連續" << ga::SIMILAR_TIMES <<"代變化小於" << ga::DIFF <<"";</p><p>int generWidth = static_cast<int>(ceil(log10(static_cast<double>(ga::GENERATION))));<br />for (int i=1; i<=ga::GENERATION; ++i)<br />{<br />selection();<br />double prevDistance = ga::vChromsome[0].distance;</p><p>srand(static_cast<unsigned>(time(NULL)));<br />crossover();<br />mutation();</p><p>//對每個染色體求距離<br />for_each(ga::vChromsome.begin()+1, ga::vChromsome.end(), ga::itor::itorDistance);<br />//進化,好解(小)在前,上一代的最優解也帶入<br />sort(ga::vChromsome.begin(), ga::vChromsome.end(), ga::less_second);</p><p>std::cout << "/n 第" ;<br />std::cout << std::setfill(' ') << std::setw(generWidth) << i;<br />std::cout << "代 最短距離="<< ga::vChromsome[0].distance;</p><p>if (prevDistance - ga::vChromsome[0].distance < ga::DIFF) ++ga::nGen;<br />else ga::nGen = 0;</p><p>if (ga::SIMILAR_TIMES < ga::nGen)break;<br />}</p><p>std::cout<<"/n/n#檢驗結果->";<br />isValid(ga::vChromsome[0].vSeqnc);</p><p>for_each(ga::vChromsome[0].vSeqnc.begin(), ga::vChromsome[0].vSeqnc.end(), ga::itor::printSequence);<br />std::cout<<"/n";</p><p>std::cout<<"/n共使用時間: " << static_cast<double>(clock()-startTime) / CLOCKS_PER_SEC<< "秒/n";<br />system("pause");<br />return 0;<br />}</p><p>bool readTSP_Data()<br />{<br />try<br />{<br />std::ifstream fin("TSP.data");<br />for (vitorCityCoor i=vCityCoors.begin(); i != vCityCoors.end(); ++i)<br />{<br />fin >> (*i).sn >> (*i).x >> (*i).y;<br />}<br />fin.close();<br />}<br />catch (...)<br />{<br />return false;<br />}<br />return true;<br />}</p><p>//貪婪演算法Right<br />int GreedyRight( std::vector<int> &cityrouter, int nCity )<br />{<br />bool bFindCity = false;<br />vitorSn iter_city;<br />for(iter_city=cityrouter.begin();iter_city!=cityrouter.end(); ++iter_city)<br />if( *iter_city == nCity )<br />{<br />bFindCity = true;<br />break;<br />}</p><p>if( bFindCity )<br />{<br />++iter_city;<br />if( iter_city == cityrouter.end() )<br />iter_city = cityrouter.begin();</p><p>return *iter_city;<br />}<br />else<br />return -1;<br />}</p><p>//貪婪演算法Left<br />int GreedyLeft( std::vector<int> &cityrouter, int nCity )<br />{<br />bool bFindCity = false;<br />vitorSn iter_city;<br />for( iter_city=cityrouter.begin();iter_city!=cityrouter.end(); ++iter_city )<br />if( *iter_city == nCity )<br />{<br />bFindCity = true;<br />break;<br />}</p><p>if( bFindCity )<br />{<br />if( iter_city == cityrouter.begin() )<br />return cityrouter.back();<br />else<br />{<br />--iter_city;<br />return *iter_city;<br />}<br />}<br />else<br />return -1;<br />}</p><p>void GreedyErase( std::vector<int> &cityrouter, int ndelcity )<br />{<br />bool bFindCity = false;<br />vitorSn iter_city;<br />for( iter_city=cityrouter.begin();iter_city!=cityrouter.end(); ++iter_city )<br />if( *iter_city == ndelcity )<br />{<br />bFindCity = true;<br />break;<br />}</p><p>if( bFindCity ) cityrouter.erase( iter_city );<br />}</p><p>//************************************<br />// Method: doCrossover<br />// FullName: doCrossover<br />// Access: public<br />// Returns: void<br />// Parameter: int nFatherA<br />// Parameter: int nFatherB<br />// Qualifier: 貪心交叉方式(Greedy Crossover),<br />// 具體演算法可參見 謝勝利,等.求解TSP問題的一種改進的遺傳演算法[J].電腦工程與應用,2002(8):58~245。見下載目錄<br />//************************************<br />void doCrossover(int nFatherA, int nFatherB)<br />{<br />int randomcity, nowopcity, nextopcity, rightA, rightB, leftA, leftB;<br />std::vector<int> SonA, SonB;</p><p>randomcity = static_cast<int>(myrand(1, NCITY));</p><p>nowopcity = randomcity;<br />SonA.push_back( nowopcity );</p><p>std::vector<int> FatherA = ga::vChromsome[nFatherA].vSeqnc;<br />std::vector<int> FatherB = ga::vChromsome[nFatherB].vSeqnc;</p><p>while( FatherA.size() > 1 && FatherB.size() > 1 )<br />{<br />rightA = GreedyRight( FatherA, nowopcity );<br />rightB = GreedyRight( FatherB, nowopcity );</p><p>if( vDistanceMatrix[nowopcity-1][rightA-1] < vDistanceMatrix[nowopcity-1][rightB-1] )<br />{<br />SonA.push_back( rightA );<br />nextopcity = rightA;<br />}<br />else<br />{<br />SonA.push_back( rightB );<br />nextopcity = rightB;<br />}</p><p>GreedyErase( FatherA, nowopcity );<br />GreedyErase( FatherB, nowopcity );<br />nowopcity = nextopcity;<br />}</p><p>nowopcity = randomcity;<br />SonB.push_back( nowopcity );<br />FatherA = ga::vChromsome[nFatherA].vSeqnc;<br />FatherB = ga::vChromsome[nFatherB].vSeqnc;</p><p>while( FatherA.size() > 1 && FatherB.size() > 1 )<br />{<br />leftA = GreedyLeft( FatherA, nowopcity );<br />leftB = GreedyLeft( FatherB, nowopcity );</p><p>if( vDistanceMatrix[nowopcity-1][leftA-1] < vDistanceMatrix[nowopcity-1][leftB-1])<br />{<br />SonB.push_back( leftA );<br />nextopcity = leftA;<br />}<br />else<br />{<br />SonB.push_back( leftB );<br />nextopcity = leftB;<br />}</p><p>GreedyErase( FatherA, nowopcity );<br />GreedyErase( FatherB, nowopcity );<br />nowopcity = nextopcity;<br />}</p><p>swap(ga::vChromsome[nFatherA].vSeqnc, SonA);<br />swap(ga::vChromsome[nFatherB].vSeqnc, SonB);<br />}</p><p>//************************************<br />// Method: crossover<br />// FullName: crossover<br />// Access: public<br />// Returns: void<br />// Qualifier: 交配<br />//************************************<br />void crossover()<br />{<br />std::vector<int> vecCrossoverIndexs;<br />double random;</p><p>for( int i=1;i<=ga::POPSIZE;i++ )<br />{<br />random = static_cast<double>(myrand(0,1));<br />if( random < ga::P_CROSSOVER )<br />vecCrossoverIndexs.push_back( i );<br />}</p><p>size_t CrossoverNumber = vecCrossoverIndexs.size();<br />if( CrossoverNumber%2 != 0 )<br />vecCrossoverIndexs.pop_back();</p><p>CrossoverNumber = vecCrossoverIndexs.size();<br />for(size_t i=0; i<CrossoverNumber; i+=2)<br />{<br />int nFatherA = vecCrossoverIndexs[i];<br />int nFatherB = vecCrossoverIndexs[i+1];</p><p>doCrossover( nFatherA, nFatherB);<br />}<br />}</p><p>void ga::itor::initChromsome(Sequence& v)<br />{<br />v.vSeqnc.resize(NCITY);</p><p>for (int i=1; i <= NCITY; ++i)<br />v.vSeqnc[i-1] = i;</p><p>std::random_shuffle(v.vSeqnc.begin(), v.vSeqnc.end());<br />v.distance = computDistance(v.vSeqnc);<br />std::cout << ".";<br />}</p><p>//************************************<br />// Method: myrand<br />// FullName: myrand<br />// Access: public<br />// Returns: double<br />// Qualifier:<br />// Parameter: double a<br />// Parameter: double b<br />// Uniform Distribution<br />// return a random num in area [a,b]<br />//************************************<br />double myrand(double a, double b)<br />{<br />double y;<br />if(a>b) {<br />printf("/nThe first parameter should be less than the second!");<br />exit(1);<br />}<br />//////////////////////////////////////////////////////////////////////////<br />//rand() can reture a number in [0, RAND_MAX]<br />y = static_cast<double>(rand())/RAND_MAX;</p><p>return (a+(b-a)*y);<br />}</p><p>//************************************<br />// Method: mutation<br />// FullName: mutation<br />// Access: public<br />// Returns: void<br />// Qualifier: 變異,對兩個隨機位置之間的城市隨機重排<br />//************************************<br />void mutation()<br />{<br />vitorSn it;<br />for (int i=1; i <= ga::POPSIZE; ++i)<br />if (ga::P_MUTATION > myrand(0,1))<br />{<br />int left = static_cast<int>(myrand(0, NCITY/2));<br />int right = static_cast<int>(myrand(NCITY/2, NCITY));<br />it = ga::vChromsome[i].vSeqnc.begin();</p><p>std::random_shuffle(it+left, it+right);<br />}<br />}</p><p>double computDistance( const std::vector<int>& v )<br />{<br />double tmp = 0.0;</p><p>for (int it=0; it<NCITY-1; ++it)<br />tmp += vDistanceMatrix[v[it]-1][v[it+1]-1];</p><p>tmp += vDistanceMatrix[v[NCITY-1]-1][v[0]-1];<br />return tmp;<br />}</p><p>//************************************<br />// Method: selection<br />// FullName: selection<br />// Access: public<br />// Returns: void<br />// Qualifier: 選擇,輪盤賭,讓前面的解(好解)以較大機率被選中<br />//************************************<br />void selection()<br />{<br />double r;<br />int label;</p><p>vTemp[0] = ga::vChromsome[0];//第一個僅僅作記錄用<br />for (int i=1; i <= ga::POPSIZE; ++i)<br />{<br />r = myrand(0, ga::vProbability[ga::POPSIZE]);<br />label = 0;<br />for (int j=0; j <= ga::POPSIZE; ++j)<br />{<br />if (r <= ga::vProbability[j])<br />{<br />label = j;<br />break;<br />}<br />}<br />vTemp[i] = ga::vChromsome[label];<br />}</p><p>swap(ga::vChromsome, vTemp);<br />}</p><p>//************************************<br />// Method: calcDistanceMatrix<br />// FullName: calcDistanceMatrix<br />// Access: public<br />// Returns: void<br />// Qualifier: 預先計算出城市間的距離矩陣供後面查詢,典型的空間換時間<br />//************************************<br />void calcDistanceMatrix()<br />{<br />double dltX, dltY;</p><p>std::vector<std::vector<double>>::iterator it = vDistanceMatrix.begin();<br />for(; it != vDistanceMatrix.end(); ++it)<br />(*it).resize(NCITY);</p><p>for (int i=0; i<NCITY; ++i)<br />for (int j=i; j<NCITY; ++j)<br />if (i == j) vDistanceMatrix[i][j] = 0.0;<br />else<br />{<br />dltX = vCityCoors[i].x - vCityCoors[j].x;<br />dltY = vCityCoors[i].y - vCityCoors[j].y;<br />vDistanceMatrix[i][j] = sqrt(static_cast<double>(dltX*dltX + dltY*dltY));<br />vDistanceMatrix[j][i] = vDistanceMatrix[i][j];<br />}<br />}

運行結果:

#讀入資料 OK
#計算城市距離矩陣 OK
#初始化255個染色體:............................................................................................................................................
................................................................................................................... OK

#開始遺傳演算法,結束條件為連續200代變化小於1e-015
    第   1代       最短距離=971.792
    第   2代       最短距離=892.135
    第   3代       最短距離=713.293
    第   4代       最短距離=670.46
    第   5代       最短距離=621.353
    第   6代       最短距離=597.599
    第   7代       最短距離=553.647
    第   8代       最短距離=523.755
    第   9代       最短距離=519.167
    第  10代       最短距離=494.994
    第  11代       最短距離=484.889
    第  12代       最短距離=477.425
    第  13代       最短距離=468.237
    第  14代       最短距離=449.349
    第  15代       最短距離=449.349
    第  16代       最短距離=446.246
    第  17代       最短距離=446.246
    第  18代       最短距離=446.246
    第  19代       最短距離=446.246
    第  20代       最短距離=445.269
    第  21代       最短距離=441.656
    第  22代       最短距離=440.679
    第  23代       最短距離=436.875
    (第  24代 到 第 225代 最短距離的小數點後三位相等,這裡不一一列出)
    第 226代       最短距離=436.875

#檢驗結果->序列正確
1 22 2 21 29 20 35 36 3 28 31 26 8 48 6 23 7 43 24 14 25 13 41 40 19 42 44 15 45
 33 39 10 30 34 50 16 11 38 9 49 5 37 17 4 18 47 12 46 51 27 32

共使用時間: 1.931秒
Press any key to continue . . .

使用了謝勝利的貪心交叉方式(Greedy Crossover),極大地提高了收斂速度。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.