這也是人工智能實驗的一個題目
- 這是一個很簡陋的遺傳算法版本,只有交叉(交配)
- 因爲種羣個體只有2個,所以就拋棄了選擇複製
- 變異暫無
#include<iostream>
#include<fstream>
using namespace std;
float city_dis[4][4];
class individual
{
public:
int gene[5]; //個體基因,5個數字,0xxx0,從城市0開始出發,到0結束
float fitness; //適應度,取20.0/distance (這個20隨便取的,重點是distance的倒數)
int distance; //計算當前基因(路線)下的總距離
individual(int gene0,int gene1,int gene2,int gene3,int gene4)
{//初始化基因
gene[0]=gene0;
gene[1]=gene1;
gene[2]=gene2;
gene[3]=gene3;
gene[4]=gene4;
//基因傳遞後執行update函數(計算fitness和distance)
update_info();
}
void set_new_gene(int *new_gene)
{
for(int i=1;i<4;++i)
{//設置新基因只會改變中間3個基因,所以循環從1到3
this->gene[i] = new_gene[i-1];//gene和傳遞進來到new_gene開始計數值不同
}
update_info();//更新個體fitness和distance
}
void update_info()
{//更新fitness和distance的函數
int new_dis = 0;
for(int i=0;i<4;++i)
{
new_dis += city_dis[this->gene[i]][this->gene[i+1]];
}
this->distance = new_dis;
this->fitness = 20.0/this->distance;
}
};
class tsp
{
public:
int ROUTE_NUM; //城市數量,用於循環
int generation_counts; //迭代次數,控制循環結束時間
int best_route[5]; //存儲目前最好的個體(路線)
int best_distance; //最好個體的路線距離
float best_fitness; //其適應度
individual *father1; //初始個體1(路線1
individual *father2; //初始個體2(路線2
tsp()
{
ROUTE_NUM = 5; //5個城市
generation_counts = 500; //迭代次數500次
memset(best_route,-1,5*sizeof(int));
best_distance = 0;
best_fitness = 0;
load_city_distance(); //從文件加載城市距離
father1 = new individual(0,2,1,3,0); //初始化個體1
//try rand father sequence //取消下面備註則會生成隨機的基因給初始個體
// int rand1[3];
// get_random_nums(rand1,3);
// father1->set_new_gene(rand1);
father2 = new individual(0,1,3,2,0); //初始化個體2
// int rand2[3];
// get_random_nums(rand2,3);
// father2->set_new_gene(rand2);
}
~tsp()
{//析構函數
delete father1;
delete father2;
}
void start_generate()
{//迭代總函數
srand(time(NULL)); //取隨機數用
while(--generation_counts >= 0) //
{
//cout<<generation_counts<<endl;
get_best_fornow(); //獲取當前種羣最好個體
switch_part_genes(); //交換兩個體的隨機2個基因,開始和結束的0基因不參加交換
}
}
void get_best_fornow()
{//判斷當前種羣是否比已有的best個體更優,有則替換
individual *now_the_best;
if(father1->fitness > father2->fitness)
{//找到兩個個體最優,並用指針指向它
now_the_best = father1;
}
else
{
now_the_best = father2;
}
if(now_the_best->fitness > this->best_fitness)
{//better one will replace the original best individual
for(int i=0;i<5;++i)
{
this->best_route[i] = now_the_best->gene[i];//替換基因
}
this->best_distance = now_the_best->distance; //替換distance
this->best_fitness = now_the_best->fitness; //替換fitness
}
}
void switch_part_genes()
{//switch 2 random genes in individual
int gene_place1[2];
int gene_place2[2];
get_random_nums(gene_place1,2);//生成1-3中2個不同隨機數給place1
get_random_nums(gene_place2,2);//生成1-3中2個不同隨機數給place2
//start to switch
swap_gene(gene_place1,gene_place2);//交換基因
father1->update_info();//更新個體信息
father2->update_info();
}
void swap_gene(int loc1[2],int loc2[2])
{ //loc1 is for father1;loc 2 for father 2
//用loc1中的2個father1基因位置來交換loc2中2個father2基因的位置
// cout<<loc1[0]<<" "<<loc1[1]<<endl;
// cout<<loc2[0]<<" "<<loc2[1]<<endl;
for(int i=0;i<2;++i)
{ //father1[i] <-> father2[i]
int temp_father1_gene = father1->gene[loc1[i]];
father1->gene[loc1[i]] = father2->gene[loc2[i]];
father2->gene[loc2[i]] = temp_father1_gene;
}
clear_conflict(father1);//交換後可能出現衝突 比如01220這種序列,需要處理衝突
clear_conflict(father2);
}
void clear_conflict(individual *ptr)
{
int mapping[4]={0,2,3,1};//mapping映射 0->0 1->2 2->3 3->1 //01220就會映射爲01320
int has_Conf_loc = has_conflict(ptr);
while(has_Conf_loc)
{
switch(has_Conf_loc)
{//根據衝突位置用映射消除衝突
case 1:
ptr->gene[1] = mapping[ptr->gene[2]];
break;
case 2:
ptr->gene[1] = mapping[ptr->gene[3]];
break;
case 3:
ptr->gene[3] = mapping[ptr->gene[3]];
break;
}
has_Conf_loc = has_conflict(ptr);
}
return;
}
int has_conflict(individual *one)
{ //可能衝突位置只有123,0和4固定爲城市0,只要1和2、1和3、2和3都不衝突,即基因不衝突
//不同返回值用於快速定位衝突位置
if(one->gene[1] == one->gene[2])
return 1;
if(one->gene[1] == one->gene[3])
return 2;
if(one->gene[2] == one->gene[3])
return 3;
return 0;
}
bool get_random_nums(int *nums,int size)
{//給nums數組生成size個不同隨機數
if(size <= 0)
{
return false;
}
if(size == 1)
{
nums[0] = rand()%3+1;//range 1-3
return true;
}
//size >= 2;
for(int i=0;i<size;++i)
{//i is the target place
nums[i] = rand()%3+1;
for(int j=0;j<i;++j)
{//j seeking the same number
if(nums[i] == nums[j])
{
nums[i] = rand()%3+1;
j=-1;
}
}
}
return true;
}
void print_best_route()
{
cout<<"\nBEST ROUTE:";
for(int i=0;i<ROUTE_NUM;++i)
{
cout<<best_route[i]<<" ";
}
cout<<endl;
cout<<"DISTANCE:"<<this->best_distance<<endl;
cout<<"FITNESS:"<<this->best_fitness<<endl;
}
void load_city_distance()
{//從文件讀取城市距離信息
char in_data[10];
ifstream in_stream;
in_stream.open("ds.txt",ios::in);
if(!in_stream.is_open())
return;
int j=0;
int k=0;
while(!in_stream.eof())
{
in_stream.getline(in_data,10);
for(int i=0;i<10;++i)
{
if(in_data[i]>= '0' && in_data[i] <= '9')
{
city_dis[j][k++] = in_data[i]-'0';
if(k==4)
{
k=0;
++j;
break;
}
}
}
}
in_stream.close();
}
};
int main()
{
tsp tsp_demo;
tsp_demo.start_generate();
tsp_demo.print_best_route();
return 0;
}
附測試截圖
ds.txt 文件內容
0 1 3 4
1 0 2 5
3 2 0 3
4 5 3 0