首先,遺傳算法可以解決很多問題。比如訓練神經網絡~,本文主要通過下面這個例子來講解:
假設有10張卡牌,上面數字爲1-10,要求將這10張卡牌分爲兩組,每組5張,第一組的5個數字只和爲36,第二組的5個數字之積爲360;
當然這個問題也可以通過其他方法求解,這裏我們要介紹的是通過遺傳算法解決。遺傳算法是一種通過模擬自然進化過程搜索最優解的方法。其 計算過程如下:
a)初始化:設置進化代數計數器t=0,設置最大進化代數T,隨機生成M個個體作爲初始羣體P(0)。
b)個體評價:計算羣體P(t)中各個個體的適應度。
c)選擇運算:將選擇算子作用於羣體。選擇的目的是把優化的個體直接遺傳到下一代或通過配對交叉產生新的個體再遺傳到下一代。選擇操作是建立在羣體中個體的適應度評估基礎上的。
d)交叉運算:將交叉算子作用於羣體。所謂交叉是指把兩個父代個體的部分結構加以替換重組而生成新個體的操作。遺傳算法中起核心作用的就是交叉算子。
e)變異運算:將變異算子作用於羣體。即是對羣體中的個體串的某些基因座上的基因值作變動。羣體P(t)經過選擇、交叉、變異運算之後得到下一代羣體P(t 1)。
f)終止條件判斷:若t=T,則以進化過程中所得到的具有最大適應度個體作爲最優解輸出,終止計算。
簡單說就是這樣子:從解決方案集合中隨機選擇兩個解決方案 ;判斷哪個方案的結果更接近想要的結果,表示爲成功方案;用成功方案代替失敗方案,或者將修改失敗方案使之更接近成功方案,形成新的解決方案集合。
代碼實現過程是這樣子的:首先初始化一個解決方案集合
private void init(){
//初始化解決方案集合
for (int i = 0; i < pop; i++){
for (int j = 0; j < len; j++){
if (random.nextDouble() < 0.5){
matr[i][j] = 0;
}else{
matr[i][j] = 1;
}
}
}
}
然後寫判斷方案的函數
private double evaluate(int n){//判斷成功方案
int sum = 0;
int prod = 1;
double sumError = 0;
double prodError = 0;
for(int i = 0; i < len; i++){
if(matr[n][i] == 0){
sum += (i + 1);
}else {
prod *= (i + 1);
}
}
sumError = (sum - sumTarget)/sumTarget;
prodError = (prod - prodTarget)/prodTarget;
return Math.abs(sumError) + Math.abs(prodError);
}
最後寫迭代遺傳
public int[] run(){
int winner = 0;
int loser = 0;
int[] ret = new int[10];
while(times-- > 1){
int a = (int)(random.nextDouble() * pop);
int b = (int)(random.nextDouble() * pop);
if(evaluate(a) < evaluate(b)){
winner = a;
loser = b;
}else{
winner = b;
loser = a;
}
for(int i = 0; i < len; i++){
if(random.nextDouble() > 0.1){//10%概率不發生交叉
matr[loser][i] = matr[winner][i];
}
if(random.nextDouble() < 0.1){//10%概率發生突變
matr[loser][i] = 1 - matr[loser][i];
}
if(evaluate(loser) == 0){//獲取最優解
ret = getResult(loser);
System.out.println("經過"+(1000 - times)+"代獲取最優解");
return ret;
}
}
if(ret[0] == 0 && times == 1){//如果經最後一次計算,獲取給特殊解:0+0+0+0+0 = 0 和 0*0*0*0*0 = 0;再重新計算一次
times++;
}
}
return ret;
}