TSP問題(換位表達,啟發式交叉,啟發式變異)C++實現

荊黎明發表於2020-11-20

旅行商問題

一 染色體表達方式

染色體的表達方式採用換位表達,它是TSP巡迴的最自然的表達,如下圖:
在這裡插入圖片描述

它的訪問順序為 3-2-5-4-7-1-6-9-8,染色體中基因的值表示城市,基因的順序表示訪問城市的順序,這種表達的搜尋空間是澄海市順序“換位”的集合,採用傳統的單點交叉時,可能導致非法的巡迴。

二 染色體交叉

本課題中的染色體交叉使用的是啟發式交叉,啟發式交叉的步驟如下(最近鄰點法):
步驟1:從一對雙親中隨機地選取一個城市最為開始城市,
步驟2:由當前城市出發,選擇一條不構成迴圈的最短邊(由雙親表達的)。若兩邊都構成迴圈,則隨機選取一個能使巡迴繼續的城市;
步驟3:如巡迴完成,停機;否則轉第2步。
在這裡插入圖片描述

啟發式交叉法明顯優於其他方法

三 染色體變異

本課題中的染色體變異使用的是啟發式變異,採用鄰域技術,以獲得後代的改進。啟發式變異過程如下:
步驟1:隨機地選出λ個基因;
步驟2:按所有選出基因的可能的換位產生鄰域;
步驟3:評估所有鄰域點,選出最好的作為變異產生的後代。
在這裡插入圖片描述

四 種群的適值函式

本課題中的適值函式為一個染色體中相鄰兩個基因的距離的加和,以及首尾兩個城市的距離。

五 種群的選擇策略

本課題中的選擇策略是從交叉後代,變異後代,和原來的父代中選擇最好的前n(n表示種群數量)個。

六 種群的初始化方法

本種群的初始化方法是從原始檔讀取城市資訊,確定城市數量,通過城市數量產生m(表示城市數量)個不同的隨機數,通過客戶的輸入的種群大小k,隨機產生k個染色體。

七 程式設計說明

1、遺傳演算法結構圖
在這裡插入圖片描述

2、種群初始化流程圖
在這裡插入圖片描述

3、染色體交叉流程圖
在這裡插入圖片描述

4、染色體變異流程圖

在這裡插入圖片描述
在這裡插入圖片描述

5、種群更新
在這裡插入圖片描述

八、程式

//  東北大學資訊科學與工程學院2000級碩士荊黎明
//  染色體的編碼方式:換位表達
//  染色體的交叉方式:啟發式交叉
//  染色體的變異方式:啟發式變異
// Created by jlm on 2020/10/19.
//
#include <iostream>
#include "class.h"
#include <ctime>	// 產生隨機數種子

using namespace std;

int main()
{
    PrintMessage();

    srand(time(NULL));	// 設定隨機數種子

    TSP tsp;

    tsp.InitiPopul();
    cout << "/*************************************種群開始迭代*************************************" << endl;
    for (int i = 0; i != tsp.GetPopulationAlgebra(); i++)
    {
        cout << i+1 << "代" << endl << endl;;
        tsp.Crossover();
        tsp.HeuristicMutation();
        tsp.Update();
        tsp.Print();
        cout << "/*************************************"<<i+1 << "代交叉變異結束" <<
             "*************************************/" << endl;
    }

    return 0;
}


//
// Created by jlm on 2020/10/19.
//

#ifndef TSP_CLASS_H
#define TSP_CLASS_H

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct Data {
    int PopulationAlgebra;	// 種群代數
    double NumPopulation;	// 種群數量
    double CrossoverRate;	// 交叉率
    double MutationRate;	// 突變率
};

typedef struct city{
    std::string name;
    double x;
    double y;
}p;

typedef struct DistTable{
    double distance;
    int table;
} DT;

// 輸出檔案資訊
void PrintMessage(void) ;

class BaseTsp{
public:
    BaseTsp();
    // 顯示路徑
    void ShowRoute(vector<int> &vi) const;

    // 獲得兩個城市的距離
    double GetTwoCityDist(int firstCity, int secondCity) const;

    // 獲得n個城市的路徑
    void GetCityDist(const vector<int> &vi, double &distance) const;

    // 生成隨機數
    void GeneratorRand(vector<int> &vi) const;

    // 獲得nCity資料
    int GetnCity(void) const;

    // 列印染色體
    void printFunc(const vector<int> &vi) const;

private:
    void ReadCityData();
    vector<p> vCity;
    int nCity;
};

class TSP: public BaseTsp
{
public:
    TSP(int Size, double CrossoverRate, double MutationRate, int PopulationAlgebra);
    TSP(struct Data data);
    TSP();
    void InitiPopul(void);
    void Crossover(void);
    void HeuristicMutation(void);
    void Update(void);
    void Print(void);

public:
    // 獲得種群代數
    int GetPopulationAlgebra(void) const;

private:
    // 兩個父代產生一個子代
    void GeneratorOffspring( const vector<int> &va, const vector<int> &vb, vector<int> &offspring) const;

    // 確定定位點
    int DeterminePoint(const vector<int> &vi, const int &value) const;

    // 為種群生成一個隨機數列,該數列作為種群中各個染色體的交叉率 、變異率
    void ForPopulRand(vector<double> &vd) const;

    // 根據適值選擇變異的子代
    void SelectOffspring(const vector<vector<int> > &mutoffspring, vector<int> &bestMuOffspring) const;

    // 基因換位,傳入一個父代基因,輸出全排列後的所有基因
    void GeneTransposition(const vector<int> &vpa, vector<vector<int> > &vvGene) const;

    // 全排列演算法 傳入一個陣列,產生一個全排列陣列
    void Permutation(vector<int> &vi, vector<int>::iterator begin,
                     vector<int>::iterator end, vector<vector<int> > &vvi) const;

    // 生成n個不同的隨機數,範圍0~n;
    void GeneratorRand(int n, int start, int end, vector<int> & vi) const;

    // 對基因進行插值
    void Interpolation(const vector<int> &position, const vector<int> &vGene, vector<vector<int> > &vvGene) const;

    // 根據適值選擇子代,子代的個數為種群的數量
    void SelectOffspring(vector<vector<int> > &vparent);

    // 尋找最後一個元素是否前面出現過
    bool findFun(vector<int> &vi) const;

    int DeleteFun(vector<int> & vtParent, vector<int> & voffspring) const;

    void InputData(struct Data & data) const;

private:
    int Size;	//種群數量
    double CrossoverRate;	//交叉率
    double MutationRate; 	// 突變率
    int PopulationAlgebra;  // 種群迭代次數

    vector<vector<int> > vParent;   // 父代染色體
    vector<vector<int> > vOffspring;    // 交叉產生的染色體
    vector<vector<int> > vMutOffspring; // 變異產生的染色體
};

#endif //TSP_CLASS_H

//
// Created by jlm on 2020/10/19.
//
#include "class.h"
#include <iostream>
#include <fstream>
#include <cstdlib>	// support for exit()	//隨機數
#include <cmath>
#include <ctime>	// 產生隨機數種子
#include <vector>
#include <algorithm> 	//  for sort() 排序函式

using namespace std;

/*
 * @BaseTsp()建構函式
 */
BaseTsp::BaseTsp()
{
    ReadCityData();
}
/*
 @ ReadCityDate() :實現檔案資料讀取
 */
void BaseTsp::ReadCityData()
{

    cout << "Enter name of data file: ";
    string filename;
    cin >> filename;


    ifstream file(filename);
    if(!file.is_open())
    {
        cerr << "檔案未能開啟:" << filename << endl;
        cerr << "程式終止\n";
        exit(EXIT_FAILURE);		// should include <cstdlib>
    }

    p City;	// 城市的結構體
    nCity = 0;
    file >> City.name >> City.x >> City.y ;
    while(file.good())
    {
        vCity.push_back(City);
        nCity++;
        file >> City.name >> City.x >> City.y ;
    }

    if(file.eof())
    {
        cout <<" 檔案資料資訊讀取完成.\n";
    }
    else if (file.fail())
    {
        cout << " 檔案資料資訊不匹配.\n";
    }
    else
    {
        cout << " 由未知原因導致程式輸入異常終止.\n";
    }
    file.close();

    cout << "資料讀取完成..." << endl;
}
/*
 * @ShowRoute:該函式實現輸出巡迴路徑
 * @ vi : 染色體
 */
void BaseTsp::ShowRoute(vector<int> &vi) const
{
    cout << "最優路徑:  " ;
    //向螢幕輸出結果
    int num = 0;
    for (auto a:vi)
    {
        cout << vCity[a - 1].name << "->" ;
        num++;
        if(num % 20 == 0)   // 20個城市換行
            cout << endl;
    }
    cout << vCity[vi[0] - 1].name << endl;
}
/*
 * @GetTwoCityDist():該函式實現兩個城市距離計算
 * @返回值:兩個城市間的距離
 * @firstCity: 第一個城市的序號
 * @secondCity: 第二個城市的序號
 */
double BaseTsp::GetTwoCityDist(int firstCity, int secondCity) const
{
    double distance;
    distance = sqrt((vCity[firstCity - 1].x - vCity[secondCity - 1].x)*(vCity[firstCity - 1].x - vCity[secondCity - 1].x)
                    +(vCity[firstCity - 1].y - vCity[secondCity - 1].y)*(vCity[firstCity - 1].y - vCity[secondCity - 1].y));
    return distance;
}

void BaseTsp::GetCityDist(const vector<int> &vi, double &distance) const
{
    distance = 0;
    int n = vi.size();
    for (int i = 0; i < n - 1; i++)
    {
        distance += GetTwoCityDist(vi[i], vi[i+1]);
    }
    // 最後回到原點
    distance += GetTwoCityDist(vi[n - 1], vi[0]);
}
/*
 *@GetnCity:獲得城市的數量
 */
int BaseTsp::GetnCity(void) const
{
    return nCity;
}
/*
 * @GeneratorRand:為染色體產生隨機數,隨機數範圍位【1,城市的數量】
 * @vi: 染色體
 */
void BaseTsp::GeneratorRand(vector<int> &vi) const	// for chromosome(染色體)
{
    int numCity = GetnCity();
    int randNum;
    int j;
    for (int i = 0; i < numCity; i++)
    {
        while(1)
        {
            randNum = rand() % numCity + 1;	// 獲取固定區間[m,n]的隨機數的公式 rand % (n - m + 1) + m
            for (j = 0; j < i; j++)
                if(vi[j] == randNum)	break;	// 檢查重複
            if (j == i)	// 沒有重複,儲存到vi中
            {
                vi.push_back(randNum);
                break;
            }
        }
    }
}

/*
 * @printFunc(): 列印染色體
 */
void BaseTsp::printFunc(const vector<int> &vi) const
{
    for (auto a:vi)
    {
        cout << a << "  ";
    }
    cout << endl;
}

/*
 * @TSP: TSP() 的建構函式
 * @ Size: 種群的數量
 * @ CrossoverRate: 種群的交叉率
 * @ MutationRate: 種群的變異率
 */
TSP::TSP(int Size, double CrossoverRate, double MutationRate, int PopulationAlgebra):BaseTsp()
{
    this -> Size = Size;
    this -> CrossoverRate = CrossoverRate;
    this -> MutationRate = MutationRate;
    this -> PopulationAlgebra = PopulationAlgebra;
}
/*
 * @TSP():建構函式
 * @data: 結構體
 */
TSP::TSP( struct Data data):BaseTsp()
{
   this -> Size = data.NumPopulation;
   this -> CrossoverRate = data.CrossoverRate;
   this -> MutationRate = data.MutationRate;
   this -> PopulationAlgebra = data.PopulationAlgebra;
}

TSP::TSP() :BaseTsp()
{
    struct Data data;
    InputData(data);
    this -> Size = data.NumPopulation;
    this -> CrossoverRate = data.CrossoverRate;
    this -> MutationRate = data.MutationRate;
    this -> PopulationAlgebra = data.PopulationAlgebra;
}
/*
 * @InitiPopul(): tsp的初始化函式,並列印產生的初始種群
 */
void TSP::InitiPopul(void)
{
    for (int i = 0; i < Size; i++)
    {
        vector<int> vi;
        BaseTsp::GeneratorRand(vi);
        vParent.push_back(vi);
    }

    // 列印出初始種群
    cout << "初始種群" <<endl;
    int i = 0;
    for (auto a:vParent)
    {
        cout << ++i << "#         ";
        printFunc(a);
    }
}

/*
 * @Crossover():種群交叉,並列印種群交叉產生的子代
 */
void TSP::Crossover(void)
{
    vector<double> vd;	// 儲存各個染色體的交叉率
    ForPopulRand(vd);

    // 尋找小於交叉率的染色體
    vector<int> vc;	// 儲存染色體小於交叉率的序號
    for (int i = 0; i != vd.size(); i++)
    {
        if (vd[i] <= CrossoverRate)
        {
            vc.push_back(i);
        }
    }

    if (vc.size()%2)	// 刪除一個數,使得產生偶數個父代
    {
        int t = rand() % vc.size();		// 隨機產生一個數
        vc.erase(vc.begin() + t);
    }

    // 隨機選擇兩個染色體進行交叉

    int nNum = vc.size()/2;	// 進行交叉的次數
    for (int i = 0; i != nNum; i++)
    {
        int vaPoint = rand() % vc.size();
        int vaValue = vc[vaPoint];	// 父代1號索引值
        vc.erase(vc.cbegin() + vaPoint);

        int vbPoint = rand() % vc.size();
        int vbValue = vc[vbPoint];	// 父代2號索引值
        vc.erase(vc.cbegin() + vbPoint);

        vector<int> offspring;	// 儲存交叉的子代

        GeneratorOffspring(vParent[vaValue],vParent[vbValue],offspring);
        vOffspring.push_back(offspring);
    }
}
/*
 * @GeneratorOffspring():兩個染色體進行交叉,產生子代染色體
 * @va: 父代染色體
 * @vb: 父代染色體
 * @offspring: 交叉產生的子代染色體
 */
void TSP::GeneratorOffspring( const vector<int> &va, const vector<int> &vb,
                              vector<int> &offspring) const
{
    int nCity = GetnCity();

    int firstCity = rand() % nCity + 1;	// 隨機選擇一個城市作為開始,隨機數的產生範圍為[1, ncity]
    offspring.push_back(firstCity);	// 第一個基因

    int vaPoint, vbPoint;
    int count = 0;

    vaPoint = DeterminePoint(va, firstCity);
    vbPoint = DeterminePoint(vb, firstCity);

    vector<int> vtParent(va.begin(),va.end());

    while (offspring.size() != nCity)
    {
        if (vaPoint == nCity - 1)
        {
            vaPoint = -1;
        }
        if (vbPoint == nCity - 1)
        {
            vbPoint = -1;
        }

        double distanceOne = GetTwoCityDist(offspring[offspring.size() - 1],va[vaPoint + 1]);
        double distanceTwo = GetTwoCityDist(offspring[offspring.size() - 1], vb[vbPoint + 1]);

        if (distanceOne >= distanceTwo)
        {
            offspring.push_back(vb[vbPoint + 1]);

            if (findFun(offspring)) //最後一個元素和前面的基因(元素)重複
            {
                offspring.push_back(va[vaPoint + 1]);
                if(findFun(offspring))
                {
                    //隨機選擇一個城市
                    int city = DeleteFun(vtParent, offspring);
                    offspring.push_back(city);
                    vaPoint = DeterminePoint(va, city);
                    vbPoint = DeterminePoint(vb, city);
                }
                else
                {
                    vaPoint = vaPoint + 1;
                    vbPoint = DeterminePoint(vb, va[vaPoint]);
                }
            }
            else
            {
                vaPoint = DeterminePoint(va, vb[vbPoint + 1]);
                vbPoint = vbPoint + 1;
            }
        }
        else
        {
            offspring.push_back(va[vaPoint + 1]);
            if (findFun(offspring))
            {
                offspring.push_back(vb[vbPoint + 1]);
                if (findFun(offspring))
                {
                    // 隨機選擇一個城市
                    int city = DeleteFun(vtParent, offspring);
                    offspring.push_back(city);
                    vaPoint = DeterminePoint(va, city);
                    vbPoint = DeterminePoint(vb, city);
                }
                else
                {
                    vaPoint = DeterminePoint(va, vb[vbPoint + 1]);
                    vbPoint = vbPoint + 1;
                }
            }
            else
            {
                vaPoint = vaPoint + 1;
                vbPoint = DeterminePoint(vb, va[vaPoint]);
            }
        }
    }
}
/*
 * @DeleteFun():刪除新增的重複城市,並隨機選擇一個城市
 * @vtParent: 父代
 * @voffspring: 子代
 */
int TSP::DeleteFun(vector<int> & vtParent, vector<int> &voffspring) const
{
    for (int i = 0; i != voffspring.size(); i++)
    {
        for (int j = 0; j != vtParent.size(); j++)
        {
            if (voffspring[i] == vtParent[j])
            {
                vtParent.erase(vtParent.begin() + j);
                j = j - 1;
            }
        }
    }

    int cityPoint = rand() % vtParent.size()  + 1;
    return vtParent[cityPoint - 1];
}

/*
 *@ findFun : 查詢染色體中前面已經出現的城市,若出現則刪除
 */

bool TSP::findFun( vector<int> &vi) const
{
    for (int i = 0; i != vi.size()- 1; i++)	// 減去2的原因是value
    {
        if (vi[i] == vi[vi.size() - 1])
        {
            vi.erase(vi.cbegin() + vi.size() - 1);
            return true;
        }
    }
    return false;
}

/*
 * @DeterminePoint():該函式的功能是確定value值在染色體的vi的位置
 * @ vi: 染色體
 * @ value: 染色體的某個值
 */
int TSP::DeterminePoint(const vector<int> &vi, const int &value) const
{
    for (int i = 0; i != vi.size(); i++)
    {
        if (value == vi[i])
        {
            return i;
        }
    }
}
/*
@function :函式功能為為種群生成一個隨機數列,該隨機數列可作為交叉率和突變率
@ vd : vd儲存的是生成的隨機數列
*/
void TSP::ForPopulRand(vector<double> &vd) const
{
    srand(time(NULL));
    double randNum;
    const int N = 99;		// 兩位小數
    for (int i = 0; i < Size; i++)
    {
        randNum = rand() %(N + 1)/(double) (N + 1);	// 生成0-1間的隨機數
        vd.push_back(randNum);
    }
}

/*
 * @ HeuristicMutation(): 該函式的動能是對染色體進行變異
 */
void TSP::HeuristicMutation(void)
{
    // 第一步:根據突變率選擇變異的父代
    vector<double>  vd;	// 儲存的是各個染色體的突變率
    ForPopulRand(vd);

    vector<int> vmu;	// 儲存需要突變的染色體序號

    for (int i = 0; i != vd.size(); i++)
    {
        if (vd[i] <= MutationRate)
        {
            vmu.push_back(i);
        }
    }

    for (int i = 0; i != vmu.size(); i++)
    {
        vector<vector<int> > vvGene;	// 儲存全排列後的所有染色體
        GeneTransposition(vParent[vmu[i]], vvGene);

        // 對於每個染色體選擇最優的子代
        vector<int> bestMuOffspring;
        SelectOffspring(vvGene, bestMuOffspring);
        vMutOffspring.push_back(bestMuOffspring);
    }
}

/*
@function:基因換位,傳入一個父代基因,輸出全排列後的所有染色體
@vpa: 表示父代基因
@vvGene: 表示生成的變異基因(已經除去了和父代相同的基因)
*/
void TSP::GeneTransposition(const vector<int> &vpa, vector<vector<int> > &vvGene) const
{

    int numGene = rand() % (vpa.size() - 2) + 2;	// 選擇numGene 個基因,範圍在[2~vpa.size()-1]

    // 對n個基因位置進行插值
    vector<int> vi;	// vi 儲存變異基因的位置
    GeneratorRand(numGene, 0, vpa.size() - 1, vi);
    Interpolation(vi, vpa, vvGene);
}

// 對基因進行插值,生成基因全排列
/*
@ position : 儲存的是隨機選擇的基因位置
@ vGene : 傳入的父代基因
@ vvGene : 生成基因全排列
*/
void TSP::Interpolation(const vector<int> &position, const vector<int> &vGene, vector<vector<int> > &vvGene) const
{
    vector<int> vTemp;	// 裝載隨機選擇的基因
    for (auto a:position)
    {
        vTemp.push_back(vGene[a]);
    }

    vector<int> vtemp(vTemp.begin(),vTemp.end());

    // 對選擇的基因進行全排列
    vector<vector<int> > vvgene;	// 儲存選擇的基因的全排列
    Permutation(vTemp, vTemp.begin(), vTemp.end(), vvgene);

    // 刪除和原始基因一樣的序列
    int numGene = vvgene.size();
    for (auto it = vvgene.cbegin(); it != vvgene.cend(); it++)
    {
        for (int j = 0; j != (*it).size(); j++)
        {
            if((*it)[j] == vtemp[j])
            {
                if(j == (*it).size() - 1)
                {
                    vvgene.erase(it);
                }
            }
            else
            {
                break;
            }
        }
        if(numGene != vvgene.size())	// 已經找到重複基因,跳出迴圈
        {
            break;
        }
    }
    // 將生成的全排列陣列分配到基因中
    vector<int> gene(vGene.begin(),vGene.end());

    for (auto a:vvgene)
    {
        int i = 0;
        for (auto b:a)
        {
            gene[position[i]] = b;
            i++;
        }
        vvGene.push_back(gene);
    }
}

/*
function: 該函式的功能是生成n個數的全排列
@vi:儲存的是需要進行全排列的n個數
@begin:儲存的是vi的首迭代器
@end: 儲存的是vi的尾迭代器
*/
void TSP::Permutation(vector<int> &vi, vector<int>::iterator begin,
                      vector<int>::iterator end, vector<vector<int> > &vvi) const
{
    if (begin == end)//遞迴的基礎部分
    {
        vector<int> temp;
        for (vector<int>::iterator it = vi.begin(); it != end; it++)
        {
            temp.push_back(*it);
        }
        vvi.push_back(temp);
    }
    else
    {
        for (auto it = begin; it != end; it++)
        {
            swap(*begin, *it);
            Permutation(vi, begin+1, end, vvi);
            swap(*begin, *it);
        }
    }
}

/*
@ n : 產生隨機數的個數
@ start :
@ end : [start end] 產生隨機數的範圍
@ vi :生成的隨機數	(儲存隨機選擇的基因位置)
*/
void TSP::GeneratorRand(int n, int start, int end, vector<int> &vi) const
{
    int randNum;
    int j;
    for (int i = 0; i != n; i++)
    {
        while(1)
        {
            randNum = rand() % (end - start + 1) + start;
            for (j = 0; j < i; j++)
            {
                if (vi[j] == randNum)
                    break;
            }
            if (j == i)
            {
                vi.push_back(randNum);
                break;
            }
        }
    }
}
/*
 * @ Update():該函式的功能是更新種群
 */
void TSP::Update(void)
{
    for (auto a:vOffspring)
    {
        vParent.push_back(a);
    }
    for (auto a:vMutOffspring)
    {
        vParent.push_back(a);
    }

    SelectOffspring(vParent);
}
/*
 * @SelectOffspring(): 該函式的功能是選擇最優的染色體(選擇的數量是初始種群的個數)
 * @ vparent: 需要進行選擇的種群
 */
void TSP::SelectOffspring(vector<vector<int> > &vparent)
{
    vector<DT> vDT;	// 儲存距離和標號

    for (int i = 0; i != vparent.size(); i++)
    {
        DT dt;
        GetCityDist(vparent[i], dt.distance);
        dt.table = i;
        vDT.push_back(dt);
    }

    sort(vDT.begin(),vDT.end(),
         []( struct DistTable &dtOne,  struct DistTable &dtTwo){ return (dtOne.distance < dtTwo.distance);
         });

    for (int i = 0; i != vDT.size(); i++)
    {
        for (int j = i + 1; j != vDT.size(); j++)
        {
            if (vDT[i].distance == vDT[j].distance)
            {
                vDT.erase(vDT.begin() + i);
                j = j - 1;
            }
        }
    }

    vector<vector<int> > VPARENT;
    for (int i = 0; i != Size; i++)
    {
        VPARENT.push_back(vparent[vDT[i].table]);
    }

    vparent.clear();	// 刪除所有元素

    for (auto a:VPARENT)
    {
        vparent.push_back(a);
    }
}

/*
 * Print(): 該函式的功能是列印種群的最優路徑和最優路徑距離
 */
void TSP::Print()
{
//    cout << "交叉產生的後代" << endl;
//    for (int i = 0; i != vOffspring.size(); i++)
//    {
//        cout << i+1 << "#         ";
//        printFunc(vOffspring[i]);
//    }
//    cout << "變異產生的後代" << endl;
//    for (int i = 0; i != vMutOffspring.size(); i++)
//    {
//        cout << i+1 << "#         ";
//        printFunc(vMutOffspring[i]);
//    }
    vOffspring.clear(); // 刪除本代產生的交叉子代
    vMutOffspring.clear();  // 刪除本代變異產生的子代
//    cout << "物競天擇,適者生存後的種群" << endl;
//    for (int i = 0; i != vParent.size(); i++)
//    {
//        cout << i+1 << "#         ";
//        printFunc(vParent[i]);
//    }

    vector<int> bestSoulation;
    SelectOffspring(vParent, bestSoulation);
    cout << "該種群中的最優解:" << endl;
    printFunc(bestSoulation);

    double distance ;
    GetCityDist(bestSoulation, distance);

    ShowRoute(bestSoulation);
    cout << "該種群中的最短路徑為:" << distance << endl;
    
    // 將distance儲存在CSV格式檔案中
    static int start = 0;
	ofstream oFile;
	if (start == 0)	// 第一代 
	{
		oFile.open("distance.csv");
		oFile << distance << endl;
		oFile.close();
	}
	oFile.open("distance.csv", ofstream::app);	// 為了保留檔案內容,必須顯示指定app模式
	oFile << distance << endl;
	oFile.close(); 
	start++;
}

/*
@ function : 根據適值選擇最好的子代
@ mutoffspring : 變異基因的全排列組合
@ bestMuOffspring:  選擇出最好的子代
*/
void TSP::SelectOffspring(const vector<vector<int> > &mutoffspring, vector<int> &bestMuOffspring) const
{
    vector<double> vd;	// 儲存城市路徑的總距離
    for (auto a:mutoffspring)
    {
        double distance;
        GetCityDist(a,distance);
        vd.push_back(distance);
    }

    double min = vd[0];
    int minKpoint = 0;
    for (int i = 0; i != vd.size(); i++)
    {
        if (vd[i] <= min)
        {
            minKpoint = i;
        }
    }

    for (auto a:mutoffspring[minKpoint])
    {
        bestMuOffspring.push_back(a);
    }
}

int TSP::GetPopulationAlgebra(void) const
{
    return (PopulationAlgebra);
}

void TSP::InputData(struct Data & data) const
{
    cout << "請輸入資料資訊:種群代數,種群數量,種群交叉率,種群突變率等" << endl << endl;
    cout << "種群代數: " ;
    cin >> data.PopulationAlgebra;
    cout << "種群數量:";
    cin >> data.NumPopulation;
    cout << "種群交叉率:";
    cin >> data.CrossoverRate;
    cout << "種群突變率:";
    cin >> data.MutationRate;
}

/*
 * @PringMessage(): 該函式的功能是列印程式資訊
 */
void PrintMessage(void)
{
	cout << "學校:東北大學" << endl;
    cout << "學院:資訊科學與工程學院" << endl;
    cout << "專業:控制科學與工程" << endl;
    cout << "學號:2000764" << endl;
    cout << "班級:2005班" << endl;
    cout << "姓名:荊黎明" << endl;

    cout << endl << endl;
    cout << "注:" << endl;
    cout << "本程式的除錯工作是在Ubuntu18.04上完成的!!!" << endl;
    cout << "染色體的編碼方式:換位表達" << endl;
    cout << "染色體的交叉方式:啟發式交叉" << endl;
    cout << "染色體的變異方式:啟發式變異" << endl;
    cout << endl << endl;
}


相關文章