1. 実験の目的:
遺伝的アルゴリズムの原理、プロセス、およびコーディング戦略に精通し、習得し、遺伝的アルゴリズムを使用して組み合わせ最適化問題を解決し、TSP 問題を解決するプロセスを理解し、結果に対する主要なパラメーターの影響をテストします。
2. 実験原理:
巡回セールスマン問題、TSP問題(Traveling Salesman 問題)は、数学の分野で有名な問題の一つです。旅行中のビジネスマンが n 都市を訪れたいとすると、行きたい道を選択する必要がありますが、そのルートの制限は、各都市は 1 回しか訪問できず、最終的には出発した元の都市に戻らなければならないことです。パス選択の目標は、必要なパス距離がすべてのパスの中で最小値になることです。TSP 問題は組み合わせ最適化問題です。この問題には NPC の計算が複雑であることがわかります。したがって、この問題の解決を簡素化できるあらゆる方法が高く評価され、注目されることになります。
遺伝的アルゴリズムの基本原理は、染色体上の遺伝子に作用して問題を解決し、適切な染色体を見つけることですが、アルゴリズムによって生成された各染色体を評価し、適合値に基づいて染色体を選択する必要があります。遺伝的アルゴリズムでは、解決すべき問題を表す多数のデジタルコード、つまり染色体をランダムに生成して初期集団を形成し、各個体に適応度を数値的に評価させます。適応度の高い個体が選択されて遺伝操作に参加し、継承操作後の個体の集合により新たな次世代の集団が形成され、次の進化が行われるこの新しい人口について。この実験では、遺伝的アルゴリズムを使用して TSP 問題の最短経路を解決する必要があります。
3. 実験内容:
1. 実験システムが提供する遺伝的アルゴリズムのコアコードを参照し、同じ人口規模、最大数の下で異なる規模(10都市、30都市、100都市など)を解決するには遺伝的アルゴリズムを使用する必要があります。反復ステップの数、および独立した操作の数 TSP 問題の結果を表 1 に記入します。
表 1 さまざまなスケールの TSP 問題を解決するための遺伝的アルゴリズムの結果
都市の大きさ |
人口規模 |
最大反復回数 |
独立した実行の数 |
最高のフィットネス |
最悪のフィットネス |
平均的なフィットネス |
平均走行時間 |
10 |
100 |
100 |
10 |
25.1652 |
25.8521 |
25.3501 |
47p |
30 |
100 |
100 |
10 |
10605.7 |
11868 |
11281.2 |
122.8秒 |
100 |
100 |
100 |
10 |
44334.9 |
47149.1 |
46117.6 |
484.2秒 |
- 母集団サイズを 100、交叉確率を 0.8、突然変異確率を 0.8 に設定し、突然変異戦略 (隣接する 2 点の交換突然変異、復帰突然変異または挿入突然変異など) と個別の選択確率の割り当てを追加します。 30 都市 (30 都市の座標は次のとおり) の TSP 問題を解くために、線形ソートまたは非線形ソートによる個別の選択確率の割り当てなどの戦略が使用され、その結果が表 2 に記入されます。
30 都市座標:
x[0]=41、x[1]=37、x[2]=54、x[3]=25、x[4]=7、x[5]=2、x[6]=68、x [7]=71、x[8]=54、x[9]=83;
y[0]=94、y[1]=84、y[2]=67、y[3]=62、y[4]=64、y[5]=99、y[6]=58、y [7]=44、y[8]=62、y[9]=69;
x[10]=64、x[11]=18、x[12]=22、x[13]=83、x[14]=91、x[15]=25、x[16]=24、x [17]=58、x[18]=71、x[19]=74;
y[10]=60、y[11]=54、y[12]=60、y[13]=46、y[14]=38、y[15]=38、y[16]=42、y [17]=69、y[18]=71、y[19]=78;
x[20]=87、x[21]=18、x[22]=13、x[23]=82、x[24]=62、x[25]=58、x[26]=45、x [27]=41、x[28]=44、x[29]=4;
y[20]=76、y[21]=40、y[22]=40、y[23]=7、y[24]=32、y[25]=35、y[26]=21、y [27]=26、および[28]=35; y[29]=50;
表 2 さまざまな突然変異戦略と個別選択確率割り当て戦略の解結果
突然変異戦略 |
個別選択確率の割り当て |
最大反復回数 |
独立した実行の数 |
最高のフィットネス |
最悪のフィットネス |
平均的なフィットネス |
平均走行時間 |
2点交換 |
体力に応じた按分 |
100 |
10 |
889.434 |
982.154 |
938.503 |
59秒 |
2点交換 |
直線的に並べ替える |
100 |
10 |
488.833 |
567.304 |
513.735 |
51秒 |
隣接する 2 つの点を交換する |
直線的に並べ替える |
100 |
10 |
1022.77 |
1104.54 |
1064.78 |
49.1秒 |
隣接する 2 つの点を交換する |
体力に応じた按分 |
100 |
10 |
878.549 |
969.802 |
939.414 |
58秒 |
3. 中国の 34 の省都のデータを考慮すると、TSP 問題を解決するには、このデータに基づいて改良された遺伝的アルゴリズムを設計する必要があります。1) 改良されたアルゴリズム戦略とコア コード、2) 改良されたアルゴリズムの主なパラメーター設定 (集団サイズ、交叉確率、突然変異確率、最大反復ステップ数など)、3) 最短距離を与える必要があります。改良されたアルゴリズムによって最終的に得られた 34 の州都間のパス値、最適な個体およびアルゴリズムの実行時間、 4) 同じパラメーター設定 (集団サイズ、交叉確率、突然変異確率、最大反復ステップ数など) を与えた場合、基本的な遺伝的アルゴリズム (改良された戦略を使用しない) を使用して、34 の州都の最短パス値、最適な個別およびアルゴリズムの実行時間を取得します。
図 1 中国の 34 の省都の位置 (1295.72)
表 3 34 の省都とピクセル座標表
街 |
チベット |
雲南省 |
四川省 |
青海省 |
寧夏回族自治州 |
甘粛省 |
内モンゴル |
黒竜江省 |
吉林省 |
遼寧 |
北京 |
天津 |
市番号 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
X座標 |
100 |
187 |
201 |
187 |
221 |
202 |
258 |
352 |
346 |
336 |
290 |
297 |
Y座標 |
211 |
265 |
214 |
158 |
142 |
165 |
121 |
66 |
85 |
106 |
127 |
135 |
街 |
河北省 |
山東省 |
河南省 |
山西省 |
陝西省 |
安徽省 |
江蘇省 |
上海 |
浙江省 |
江西省 |
湖北省 |
湖南省 |
市番号 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
X座標 |
278 |
296 |
274 |
265 |
239 |
302 |
316 |
334 |
325 |
293 |
280 |
271 |
Y座標 |
147 |
158 |
177 |
148 |
182 |
203 |
199 |
206 |
215 |
233 |
216 |
238 |
街 |
貴州省 |
広西チワン族自治区 |
広東省 |
福建省 |
海南 |
マカオ |
香港 |
台湾 |
重慶 |
新疆 |
||
市番号 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
||
X座標 |
221 |
233 |
275 |
322 |
250 |
277 |
286 |
342 |
220 |
104 |
||
Y座標 |
253 |
287 |
285 |
254 |
315 |
293 |
290 |
263 |
226 |
77 |
x[0]=100、x[1]=187、x[2]=201、x[3]=187、x[4]=221、x[5]=202、x[6]=258、x [7]=352、x[8]=346、x[9]=336;
y[0]=211、y[1]=265、y[2]=214、y[3]=158、y[4]=142、y[5]=165、y[6]=121、y [7]=66、y[8]=85、y[9]=106;
x[10]=290、x[11]=297、x[12]=278、x[13]=296、x[14]=274、x[15]=265、x[16]=239、x [17]=302、x[18]=316、x[19]=334;
y[10]=127、y[11]=135、y[12]=147、y[13]=158、y[14]=177、y[15]=148、y[16]=182、y [17]=203、y[18]=199、y[19]=206;
x[20]=325、x[21]=293、x[22]=280、x[23]=271、x[24]=221、x[25]=233、x[26]=275、x [27]=322、x[28]=250、x[29]=277;
y[20]=215、y[21]=233、y[22]=216、y[23]=238、y[24]=253、y[25]=287、y[26]=285、y [27]=254、および[28]=315; y[29]=293;
x[30]=286、x[31]=342、x[32]=220、x[33]=104;
y[30]=290、y[31]=263、y[32]=226、y[33]=77;
3.1 結果:
3.1.1 ここに 2 つの実験結果があります。違いは最初の開始点が異なるだけです
① 図 2 に示すようにパスを描画します (Python ベース、開始点 15)。
図 2 最適解を示すプロット
最短経路長 1532.3994414550848
パス表現: [23、32、24、1、2、0、33、3、5、4、12、14、16、22、21、27、31、30、26、29、28、25、20、 19、18、17、13、11、9、8、7、10、6]
パスの長さは反復回数とともに減少します。
図3 反復回数と最適解の関係
② 図に示すようにパスを描画します (Python ベース、開始点 32)。
図 4 は、最適解を示すプロットです。
最短パス長: 1551.0699954694958
パス表現: [1、28、25、24、18、20、19、31、27、29、30、26、23、21、22、16、14、17、13、9、8、7、11、 10、12、15、6、4、5、0、33、3、2]
パスの長さは反復回数とともに減少します。
図5 最適解と反復回数の関係
3.1.2
改善されない場合は元のプログラムを使用し、パラメータは次のように設定されます(C++ ベース)。
染色体長: 34
最大反復ステップ: 500
人口サイズ: 100
クロスオーバー確率: 0.5
突然変異確率 0.15
選抜操作:適応度に応じて個体の選抜確率を分配し、ルーレットにより個体を選抜する
クロスオーバー操作: PMX クロスオーバー
突然変異操作: 2 つの隣接する点を交換する
結果を図 6 に示します。
図 6 結果
最適なパス長は 6246.62 です。
パス: 32-20-18-21-28-29-26-24-13-30-12-10-31-33-2-3-1-7-9-4-15-11-0-5- 8-6-17-16-23-25-19-22-27-14
実行時間: 214.6秒
改良されたアルゴリズムが非常に効果的であることがわかります。
3.2改善されたアルゴリズム戦略とコアコード:
①パラメータ設定:
#母数
カウント=300
#時間を改善する
改善数=10000
#進化時間
itter_time=3000
#強者の定義確率を設定します。つまり、人口の上位 30% が強者です
保持率=0.3
#弱者の生存確率を設定する
ランダム選択レート=0.5
#突然変異率
突然変異率=0.1
②パスコーディング:
都市に 0、1、2、3...33、染色体 {x1、x2、x3...x33} と番号を付けます。これは、 x1 から始まり、 x2、x3...x33 を経て x1 に戻ることを意味します。開始点は任意に設定できますが、このプログラムでは 15 に設定されています。
③ 母集団を初期化します。
プログラムの実行速度を速くするには、初期集団の選択でいくつかのより優れた個体を選択する必要があります。まず、古典的な近似アルゴリズム (改良された円アルゴリズム) を使用して、より適切な初期母集団を取得します。アルゴリズムの考え方は、{1、2、... 33} などの染色体をランダムに生成し、2 つの都市の連続する位置を任意に交換し、合計距離が減少した場合に染色体を更新および変更することです。これ以上変更できなくなるまで繰り返します。
コード:
#人口を初期化する
人口 = []
範囲内の i の場合 (カウント):
# 個人をランダムに生成する
x = インデックス.コピー()
ランダムシャッフル(x)
改善(x)
人口.append(x)
#改良
デフォルト改善(x):
i=0
距離=get_total_ distance(x)
while i<improve_count:
# randint [a,b]
u=random.randint(0,len(x)-1)
v = ランダム.randint(0, len(x)-1)
u!=v の場合:
new_x=x.copy()
t=new_x[u]
新しい_x[u]=新しい_x[v]
新しい_x[v]=t
new_ distance=get_total_ distance(new_x)
新しい距離<距離の場合:
距離=新しい距離
x=new_x.copy()
それ以外:
続く
i+=1
④戦略の選択:
ルーレット ホイール法は最もよく使用される選択戦略ですが、この戦略では大きなサンプリング エラーが発生する可能性があるため、自然選択を使用して各都市間の距離を計算し、行列に格納します。適応性の強い染色体を選択し、適応性は低いが生き残っている染色体を選択します(ランダム選択)。
コアコード:
# 自然な選択
デフォルトの選択(母集団):
# 合計距離を小さいものから大きいものに並べ替えます
Graded = [[get_total_ distance(x), x] (母集団内の x の場合)]
Graded = [sorted(graded) の x の x[1]]
# 最も適応性の高い染色体を選択する
保持長 = int(len(段階的) * 保持率)
親 = 等級[:retain_length]
# 適応性は低いが生き残っている染色体を選択する
Graded[retain_length:] の染色体の場合:
ランダム.ランダム() < ランダム選択レートの場合:
親.追加(染色体)
両親を返す
⑤バリエーション戦略:
与えられた突然変異率に従って、選択された突然変異個体のうち 1<u<v<w<33 を満たす 3 つの整数をランダムに選択し、v と u の間 (u と v を含む) の遺伝子セグメントを後で w に挿入します。元の隣接する 2 つの点スワップ変異と 2 点スワップの変異戦略を置き換えます。
コアコード:
#突然変異
デフォルトの突然変異(子):
range(len(children)) 内の i の場合:
ランダム.ランダム() < 変異率の場合:
child=子供たち[i]
u=random.randint(1,len(子)-4)
v = ランダム.randint(u+1, len(子)-3)
w= ランダム.randint(v+1, len(子)-2)
child=子供たち[i]
子=子[0:u]+子[v:w]+子[u:v]+子[w:]
4. 実験レポートとソースプログラムを提出します。
3.実験結果:
実験内容1の結果:
表 1 さまざまなスケールの TSP 問題を解決するための遺伝的アルゴリズムの結果
都市の大きさ |
人口規模 |
最大反復回数 |
独立した実行の数 |
最高のフィットネス |
最悪のフィットネス |
平均的なフィットネス |
平均走行時間 |
10 |
100 |
100 |
10 |
25.1652 |
25.8521 |
25.3501 |
47p |
30 |
100 |
100 |
10 |
10605.7 |
11868 |
11281.2 |
122.8秒 |
100 |
100 |
100 |
10 |
44334.9 |
47149.1 |
46117.6 |
484.2秒 |
実験内容2の結果:
表 2 さまざまな突然変異戦略と個別選択確率割り当て戦略の解結果
突然変異戦略 |
個別選択確率の割り当て |
最大反復回数 |
独立した実行の数 |
最高のフィットネス |
最悪のフィットネス |
平均的なフィットネス |
平均走行時間 |
2点交換 |
体力に応じた按分 |
100 |
10 |
889.434 |
982.154 |
938.503 |
59秒 |
2点交換 |
直線的に並べ替える |
100 |
10 |
488.833 |
567.304 |
513.735 |
51秒 |
隣接する 2 つの点を交換する |
直線的に並べ替える |
100 |
10 |
1022.77 |
1104.54 |
1064.78 |
49.1秒 |
隣接する 2 つの点を交換する |
体力に応じた按分 |
100 |
10 |
878.549 |
969.802 |
939.414 |
58秒 |
実験コンテンツ 3 の結果 (実験コンテンツ 3 にあります):
パスを図 2 に示します。
最短経路長 1532.3994414550848
パス表現: [23、32、24、1、2、0、33、3、5、4、12、14、16、22、21、27、31、30、26、29、28、25、20、 19、18、17、13、11、9、8、7、10、6]
4. 実験的思考と経験:
1. さまざまなスケールの TSP 問題を解決するための遺伝的アルゴリズムのアルゴリズム パフォーマンスを分析します。
都市の規模が大きくなると、反復回数も多くなり、最適解の探索に時間がかかり、結果が得られるまでの待ち時間も長くなります。
2. 1 つの突然変異戦略と 1 つの個別選択確率分布戦略を追加し、30 都市で TSP 問題を解く際のアルゴリズム結果に対するさまざまな突然変異戦略と個別選択確率分布戦略の影響を比較します。
個体を選択するための隣接 2 点突然変異と線形ソートを追加しました。
突然変異戦略:
void change1(vector<int>& K, int N){//突然変異戦略: 2 つの隣接する点の間で突然変異を交換します。
int i = next_int() % N;
swap(K[i], K[(i + 1) % N]);
}
個別の選択戦略:
if(make_p==1)//線形ソート
{
for(int i=0;i<popsize;i++)
ps[i]=(200-2*i)/popsize*(popsize+1);
}
実験結果から、線形ソートの方が優れており、ランダム 2 点交換戦略の方が隣接 2 点交換戦略より明らかに優れています。
3. 34 都市の TSP 問題の解決結果に対する遺伝的アルゴリズムの改善された戦略の影響を比較分析します。
主な理由は、適応度の選択が比較的大幅に改善されたためです。より優れた個体が最初に選択され、いくつかの悪い個体がランダムに選択されます。一部のパラメータ、選択、突然変異のコードを改善することで、改善を行わなかった場合、最終的な演算で得られる最適解は図 7 に示すように約 7.8 千となり、精度は十分とは言えません。
図 7 改善されない実行結果
4. 実験の経験を要約します。
他にも次のような多くの改善戦略があります。
①貪欲アルゴリズムを使用して人口を初期化し、各世代の基本的な考え方は次のとおりです。まず最初の遺伝子として n 個の都市から現在の都市をランダムに選択し、次に残りの n-1 個の都市から都市 cnext (cnext) を見つけます。 cnext は ccurrent に最も近い都市です) を 2 番目の遺伝子として、残りの n-2 都市から cnext+1 の都市 (cnext+1 は cnext に最も近い都市です) を 3 番目の遺伝子として検索し、以下同様に n をトラバースするまで続けます。これまでの都市。貪欲アルゴリズムによって生成される一部の母集団の割合は大きくないため、初期母集団の全体的な品質は向上しますが、初期母集団の多様性には影響を与えず、最適化速度の向上に役立ちます。コードにあまり慣れていないため、人口を初期化する貪欲なアルゴリズムにコードを変更することに失敗しました。
② 適応度を適当に拡大して端数部分を考慮することも可能ですが、実験の結果からするとあまり意味がなく、最適解は比較的平均的であり、距離もかなり大きいままです。
③改良型交叉演算子:基本的な遺伝的アルゴリズムで一般的に使用される2点交叉演算子で、親個体の2点間の遺伝子のみを交叉する方法であり、2点以外の遺伝子は変化しないか、ノードの重複によりブラインドになります。親の優れた遺伝子は効果的に受け継がれません。2点3線ランダム交叉が可能です。
改善されていないソースコード:
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<time.h>
using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
#define PB push_back
#define MP make_pair
int next_int()
{
return rand()*(RAND_MAX+1)+rand();
}
double next_double()
{
return (double(rand()*(RAND_MAX+1)+rand()))/((RAND_MAX+1)*RAND_MAX+RAND_MAX);
}
void pmx(VI& a,VI& b,int pointcnt)//PMX交叉
{
int sa=next_int()%pointcnt,sb=next_int()%pointcnt;//随机选择两交叉位
int temp;
if (sa>sb)
{
temp=sa;
sa=sb;
sb=temp;
}//保证交叉位sa<=sb
VI aa(pointcnt),bb(pointcnt);
int i;
for(i=0;i<pointcnt;i++)
{
aa[i]=a[i],bb[i]=b[i];
}
VI m1(pointcnt,-1);
VI m2(pointcnt,-1);
VI v1tov2(pointcnt,-1);
for(i=sa;i<=sb;i++)
{
m1[aa[i]]=-2; //m1存放aa非交叉段可代换的基因
m2[bb[i]]=-2; //m2存放aa非交叉段可代换的基因
}
for(i=0;i<pointcnt;i++) {
if(m2[i]==m1[i])//去掉m1和m2中重复代换的基因
{
m2[i]=-1;
m1[i]=-1;
}
}
int aaa=0;
for(i=sa;i<=sb;i++)
{
if ((m1[aa[i]]==-2)&&(m2[bb[i]]==-2))
{
v1tov2[aa[i]]=bb[i];//v1tov2存放首先可以确定的互换基因
m1[aa[i]]=-1;
m2[bb[i]]=-1;
aaa++;
}
}
if(aaa!=(sb-sa+1))
{
for(i=0;i<pointcnt;i++)
if (m1[i]==-2)
{
int aflag=0;
for(int j=0;j<pointcnt;j++)
if( (m2[j]==-2) && (aflag==0))//寻找并确定可以互换的基因
{
v1tov2[i]=j;
aflag=1;
aaa++;
m2[j]=-1;
m1[i]=-1;
}
}
}
for(i=sa;i<=sb;i++) {
swap(aa[i],bb[i]); //交换sa到sb之间的基因串
}
for(i=0;i<pointcnt;i++)//查找染色体aa中sa之前和sb之后的基因是否有重复
{
if ((i<sa)||(i>sb))
for (int j=sa;j<=sb;j++)
{
if(aa[i]==aa[j]) //有重复基因
{
for(int k=0;k<pointcnt;k++)
if(aa[i]==v1tov2[k])
aa[i]=k; //进行互换
}
}
}
for(i=0;i<pointcnt;i++)//查找染色体bb中sa之前和sb之后的基因是否有重复
{
if ((i<sa)||(i>sb))
for (int j=sa;j<=sb;j++)
{
if(bb[i]==bb[j]) //有重复基因
bb[i]=v1tov2[bb[i]]; //进行互换
}
}
a=aa;
b=bb;
}
vector<double> x,y;
double fitness(const VI& v,int pointcnt)//计算适应度
{
double r=0;
for(int i=0;i<pointcnt;i++)
{
double dx=x[v[i]]-x[v[(i+1)%pointcnt]];
double dy=y[v[i]]-y[v[(i+1)%pointcnt]];
r+=sqrt(dx*dx+dy*dy);//个体的适应度为相邻两城市之间的距离平方的平方根和
}
return 1.0/r;
}
void change0(vector<int>& K,int N)//变异策略:两点互换
{
int i=next_int()%N;
int d=next_int()%(N-1);
int j=(i+1+d)%N;
swap(K[i],K[j]);
}
void change1(vector<int>& K, int N){//变异策略:相邻两点互换变异
int i = next_int() % N;
swap(K[i], K[(i + 1) % N]);
}
void mutate(VI& route,int mutate_type,int pointcnt)
{
if(mutate_type==0)//两点互换
change0(route,pointcnt);
if(mutate_type==1)//相邻两点互换变异
change1(route,pointcnt);
}
bool pair_dec(const pair<double,VI*>& a,const pair<double,VI*>& b)
{
return a>b;
}
class other_population
{
public:
int popsize,pointcnt;//种群规模,染色体长度
double pc,pm;//交叉概率,变异概率
vector<pair<double,VI*> >pop;//种群
pair<double,VI*> bestofpop;//最好个体
int cross_type;//交叉类型
int mutate_type;//变异类型
int make_p;//个体概率分配策略类型
int select_type;//个体选择类型
int toursize;//竞赛规模
double bestp;//最好个体选择概率
other_population(int a,int b,int c,int f,int g,double d,double e,int h,double j,int m)
{
popsize=a,pointcnt=b,cross_type=c,mutate_type=f,make_p=g,pc=d,pm=e,toursize=h,bestp=j,select_type=m;
for(int i=0;i<popsize;i++)//初始化种群
{
VI* v=new VI(pointcnt);
for(int j=0;j<pointcnt;j++)
(*v)[j]=j;
random_shuffle(v->begin(),v->end());
pop.PB(MP(fitness(*v,pointcnt),v));
}
sort(pop.begin(),pop.end(),pair_dec);
bestofpop.first=pop[0].first;//初始时最好个体的适应度
bestofpop.second=new VI(*pop[0].second);//初始时最好个体的染色体
}
~other_population()
{
for(int i=0;unsigned(i)<pop.size();i++)
delete pop[i].second;
delete bestofpop.second;
}
void next()//产生下一代种群
{
vector<double> ps(popsize);
if(make_p==0) //按适应度比例分配个体的选择概率
{
double sum=0;
for(int i=0;i<popsize;i++)
sum+=pop[i].first;//计算种群的适应度和
for(int i=0;i<popsize;i++)
ps[i]=pop[i].first/sum;
}
if(make_p==1)//线性排序
{
for(int i=0;i<popsize;i++)
ps[i]=(200-2*i)/popsize*(popsize+1);
}
if(select_type==0)//轮盘赌选择个体
{
vector<pair<double,VI*> > select_res;
vector<double> addsum(popsize);
for(int i=0;i<popsize-1;i++)//计算个体的累计概率
{
if(i==0)
addsum[i]=ps[0];
else
addsum[i]=addsum[i-1]+ps[i];
}
addsum[popsize-1]=1;//1.5;
for(int i=0;i<popsize;i++)
{
double rd=next_double();
int r=lower_bound(addsum.begin(),addsum.end(),rd)-addsum.begin();
VI* v=new VI(*pop[r].second);
select_res.PB(MP(fitness(*v,pointcnt),v));
}
for(int i=0;i<popsize;i++)
delete pop[i].second;
pop=select_res;
}
for(int cc=0;cc<popsize/2;cc++)//随机选择两个个体,然后进行交叉
{
int a=next_int()%popsize;
int b=(a+1+(next_int()%(popsize-1)))%popsize;
if(next_double()<pc)//随机数小于交叉概率,进行交叉
{
if(cross_type==0)//pmx交叉
pmx(*pop[a].second,*pop[b].second,pointcnt);
pop[a].first=fitness(*pop[a].second,pointcnt);//计算交叉后个体a的适应度
if(bestofpop.first<pop[a].first)//更新最好个体
{
bestofpop.first=pop[a].first;
delete bestofpop.second;
bestofpop.second=new VI(*pop[a].second);
}
pop[b].first=fitness(*pop[b].second,pointcnt);//计算交叉后个体b的适应度
if(bestofpop.first<pop[b].first)//更新最好个体
{
bestofpop.first=pop[b].first;
delete bestofpop.second;
bestofpop.second=new VI(*pop[b].second);
}
}
}
for(int i=pop.size()-1;i>=0;i--)//进行变异
if(next_double()<pm)//随机数小于变异概率,进行变异
{
mutate(*pop[i].second,mutate_type,pointcnt);//变异
pop[i].first=fitness(*pop[i].second,pointcnt);//计算变异后个体的适应度
}
sort(pop.begin(),pop.end(),pair_dec);//从大到小排序
if(bestofpop.first<pop[0].first)//更新最好个体
{
delete bestofpop.second;
bestofpop.first=pop[0].first;
bestofpop.second=new VI(*pop[0].second);
}
}
};
int main()
{
srand((unsigned)time(NULL));
int CASNUM,POINTCNT,POPSIZE,GENERATIONS;
//scanf("%d",&CASNUM);//输入实验次数
CASNUM=10;//输入实验次数
cout << "实验次数:" << CASNUM << "次" << endl;
//scanf("%d%d%d",&POINTCNT,&POPSIZE,&GENERATIONS);//输入染色体长度(城市数),种群规模,最大迭代步数
POINTCNT=30;//输入染色体长度(城市数)
POPSIZE=100,GENERATIONS=100;//输入种群规模,最大迭代步数
x.resize(POINTCNT);
y.resize(POINTCNT);
// x[0]=0, x[1]=1.1,x[2]=3.5,x[3]=3,x[4]=7,x[5]=8,x[6]=4,x[7]=4.5,x[8]=9,x[9]=2;
//x[10]=10, x[11]=11.1,x[12]=13.5,x[13]=13,x[14]=17,x[15]=18,x[16]=14,x[17]=14.5,x[18]=19,x[19]=12;
// y[0]=1.1,y[1]=3,y[2]=2,y[3]=4,y[4]=5.1,y[5]=8,y[6]=4,y[7]=4.5,y[8]=9,y[9]=2;
//y[10]=11.1,y[11]=13,y[12]=12,y[13]=14,y[14]=15.1,y[15]=18,y[16]=14,y[17]=14.5,y[18]=19,y[19]=12;
x[0]=41, x[1]=37,x[2]=54,x[3]=25,x[4]=7,x[5]=2,x[6]=68,x[7]=71,x[8]=54,x[9]=83;
y[0]=94,y[1]=84,y[2]=67,y[3]=62,y[4]=64,y[5]=99,y[6]=58,y[7]=44,y[8]=62,y[9]=69;
x[10]=64,x[11]=18,x[12]=22,x[13]=83,x[14]=91,x[15]=25,x[16]=24,x[17]=58,x[18]=71,x[19]=74;
y[10]=60,y[11]=54,y[12]=60,y[13]=46,y[14]=38,y[15]=38,y[16]=42,y[17]=69,y[18]=71,y[19]=78;
x[20]=87,x[21]=18,x[22]=13,x[23]=82,x[24]=62,x[25]=58,x[26]=45,x[27]=41,x[28]=44, x[29]=4;
y[20]=76,y[21]=40,y[22]=40,y[23]=7,y[24]=32,y[25]=35,y[26]=21,y[27]=26,y[28]=35; y[29]=50;
cout<<"城市数="<<POINTCNT<<endl;
cout<<"各城市坐标:"<<endl;
//srand((unsigned)time(NULL));
/* for(int i=10;i<POINTCNT;i++)
{
x[i]=next_int()%1000;y[i]=next_int()%1000;
}*/
for(int i=0;i<POINTCNT;i++)
{
//scanf("%lf%lf",&x[i],&y[i]);//输入各个城市的坐标
cout<<"["<<x[i]<<", "<<y[i]<<"]"<<endl;//输出各个城市的坐标
}
cout<<"染色体长度:"<<POINTCNT<<endl;
cout<<"最大迭代步数:"<<GENERATIONS<<endl;
cout<<"种群规模:"<<POPSIZE<<endl;
int select_type,make_p_type,k,cross_type,mutate_type;
double q,pc,pm;
select_type=0,make_p_type=1,k=5;//输入个体选择方法类型,个体选择概率分配类型,竞赛规模
q=0.5,pc=0.8,pm=0.8;//输入最好个体选择概率,交叉概率,变异概率
cross_type=0,mutate_type=0;//输入交叉类型,变异类型
cout<<"交叉概率:"<<pc<<endl;
cout<<"变异概率"<<pm<<endl;
cout<<"选择操作:按适应度比例分配个体的选择概率,轮盘赌选择个体"<<endl;
cout<<"交叉操作:PMX交叉"<<endl;
cout<<"变异操作:两点互换"<<endl;
double best=1e9,worst=0,sum=0;
VI res;
clock_t start_time;
start_time=clock();
cout << endl;
cout << "正在计算中......" << endl;
for(int cas=0;cas<CASNUM;cas++)//
{
other_population gen(POPSIZE,POINTCNT,cross_type,mutate_type,make_p_type,pc,pm,k,q,select_type);
for(int g=0;g<GENERATIONS;g++)//进行迭代进化
gen.next();
if(best>1.0/gen.bestofpop.first)//更新最好适应度
{
best=1.0/gen.bestofpop.first;
res=*gen.bestofpop.second;//存放最好个体的染色体
}
if(worst<1.0/gen.bestofpop.first)//更新最差适应度
worst=1.0/gen.bestofpop.first;
sum+=1.0/gen.bestofpop.first;//计算各次最好个体的适应度之和
}
cout << endl;
cout << CASNUM << "次遗传算法求解的结果如下:" << endl;
clock_t end_time=clock();
double durTime=double(end_time-start_time);
sum/=CASNUM;//计算平均适应度
cout<<"最好适应度:"<<best<<"\n"<<"最差适应度:"<<worst<<"\n"<<"平均适应度:"<<sum<<"\n";
cout<<"输出最好解:";
for(int i=0;i<POINTCNT;i++)//输出解
{
cout<<res[i];//输出各城市
if (i<POINTCNT-1)
cout<<"-";
}
cout<<endl;
cout<<"平均运行时间:"<<durTime/CASNUM<<"s"<<endl;
cout<<endl;
return 0;
}