1. 程式人生 > >[work] 演算法學習筆記 (爬山法,模擬退火演算法,遺傳演算法)

[work] 演算法學習筆記 (爬山法,模擬退火演算法,遺傳演算法)

在優化問題中,有兩個關鍵點

代價函式

確定問題的形式和規模之後,根據不同的問題,選擇要優化的目標。如本文涉及的兩個問題中,一個優化目標是使得航班選擇最優,共計12個航班,要使得總的票價最少且每個人的等待時間之和最小。第二個問題是學生選擇宿舍的問題,每個學生可以實現填報志願,如果安排的宿舍與志願完全一致,則代價為0,與第二志願一致,代價為1,如果沒有和志願一致,代價為3。 故,抽象問題的能力很重要,如何將自己要優化的目標量化的表達出來,是解決優化函式的關鍵。如在普通的數值優化問題中,可選擇當前值與目標值距離的絕對之差,或者使用平方損失函式,均可。

值域

值域是確定搜尋的範圍。一個可行解的範圍是多少,比如學生選宿舍的問題,一共學校有100間宿舍,編號為1-100,那麼這個數值優化問題的每個可行解的範圍均在100之內。不同的問題對應不同的可行解,也要具體問題具體分析。

隨機搜尋演算法

隨機搜尋演算法是最簡單的優化搜尋演算法,它只適用於代價函式在值域範圍內沒有任何變化規律的情況。即找不到任何使得代價下降的梯度和極小值點。 我們只需要在值域範圍內生成足夠多的可行解,然後分別計算每個可行解的代價,根據代價選擇一個最小的可行解作為隨機搜尋的最優解即可。

# 搜尋方法1: 隨機搜尋演算法
# 函式會作1000次隨機猜測,記錄總代價最低的方法. domain為航班號的範圍(0-9),共有5個人,因此共有10項

def randomoptimize(self, domain):
    best_sol = []
    bestcost = 99999
    for i in range(1000):
        sol = [0] * len(domain)
        for j in range(len(domain) / 2):  # 人數
            sol[2 * j] = random.randint(domain[2 * j][0], domain[2 * j][1])
            sol[2 * j + 1] = random.randint(domain[2 * j + 1][0], domain[2 * j + 1][1])

        print sol[:]
        newcost = self.schedulecost(sol)
        if newcost < bestcost:
            bestcost = newcost
            best_sol = sol
        else:
            continue
    self.printschedule(best_sol)
    print "隨機搜尋演算法的結果的最小代價是:", bestcost
    return best_sol

爬山法

爬山法假設當前解和周圍的解是有變化規律的,如,當前解得下方有一個代價較小的解,則我們就認為,沿著這個方向走,解會越來越小。步驟為:首先選擇一個解作為種子解,每次尋找與這個解相近的解,如果相近的解中有代價更小的解,則把這個解作為種子解。而如果周圍的解都比該解的代價大,則表示已經到達了局部極小值點,搜尋停止。

    # 搜尋演算法2:爬山法
    # 首先隨機選擇一個解作為種子解,每次尋找這個種子相近的解,如果相近的解有代價更小的解,則把這個新的解作為種子
    # 依次迴圈進行,當迴圈到某種子附近的解都比該種子的代價大時,說明到達了局部極小值點,搜尋結束
    def hillclimb(self, domain):
        # 隨機產生一個航班序列作為初始種子
        seed = [random.randint(domain[i][0], domain[i][1]) for i in range(len(domain))]
        while 1:
            neighbor = []
            # 迴圈改變解的每一個值產生一個臨近解的列表
            for i in range(len(domain)):
                # 下列判斷是為了將某一位加減1後不超出domain的範圍
                # print seed
                if seed[i] > domain[i][0]:
                    newneighbor = seed[0:i] + [seed[i] - 1] + seed[i + 1:]
                    # print newneighbor[:]
                    neighbor.append(newneighbor)
                if seed[i] < domain[i][1]:
                    newneighbor = seed[0:i] + [seed[i] + 1] + seed[i + 1:]
                    # print newneighbor[:]
                    neighbor.append(newneighbor)

            # 對所有的臨近解計算代價,排序,得到代價最小的解
            neighbor_cost = sorted(
                [(s, self.schedulecost(s)) for s in neighbor], key=lambda x: x[1])

            # 如果新的最小代價 > 原種子代價,則跳出迴圈
            if neighbor_cost[0][1] > self.schedulecost(seed):
                break

            # 新的代價更小的臨近解作為新的種子
            seed = neighbor_cost[0][0]
            print "newseed = ", seed[:], " 代價:", self.schedulecost(seed)
        # 輸出
        self.printschedule(seed)
        print "爬山法得到的解的最小代價是", self.schedulecost(seed)
        return seed

模擬退火演算法

從一個問題的原始解開始,用一個變數代表溫度,這一溫度開始時非常高,而後逐步減低。在每一次迭代期間,演算法會隨機選中題解中的某個數字,使其發生細微變化,而後計算該解的代價。關鍵的地方在於計算出該解的代價後,如果決定是否接受該解。 如果新的成本更低,則新的題解就會變成當前題解,這與爬山法類似;如果新的成本更高,則新的題解與概率 P 被接受。這一概率會隨著溫度T的降低而降低。即演算法開始時,可以接受表現較差的解,隨著退火過程中溫度的不斷下降,演算法越來越不可以接受較差的解,知道最後,它只會接受更優的解。 ** 其中P = exp[-(newcost - oldcost)/ T ] 其中newcost是新解的成本,oldcost是當前成本,T為當前溫度。演算法以概率P接受新的解。**

    # 搜尋演算法4:模擬退火演算法
    # 引數:T代表原始溫度,cool代表冷卻率,step代表每次選擇臨近解的變化範圍
    # 原理:退火演算法以一個問題的隨機解開始,用一個變量表示溫度,這一溫度開始時非常高,而後逐步降低
    #      在每一次迭代期間,算啊會隨機選中題解中的某個數字,然後朝某個方向變化。如果新的成本值更
    #      低,則新的題解將會變成當前題解,這與爬山法類似。不過,如果成本值更高的話,則新的題解仍
    #      有可能成為當前題解,這是避免區域性極小值問題的一種嘗試。
    # 注意:演算法總會接受一個更優的解,而且在退火的開始階段會接受較差的解,隨著退火的不斷進行,演算法
    #      原來越不能接受較差的解,直到最後,它只能接受更優的解。
    # 演算法接受較差解的概率 P = exp[-(highcost-lowcost)/temperature]
    def annealingoptimize(self, domain, T=10000.0, cool=0.98, step=1):
        # 隨機初始化值
        vec = [random.randint(domain[i][0], domain[i][1]) for i in range(len(domain))]

        # 迴圈
        while T > 0.1:
            # 選擇一個索引值
            i = random.randint(0, len(domain) - 1)
            # 選擇一個改變索引值的方向
            c = random.randint(-step, step)  # -1 or 0 or 1
            # 構造新的解
            vecb = vec[:]
            vecb[i] += c
            if vecb[i] < domain[i][0]:  # 判斷越界情況
                vecb[i] = domain[i][0]
            if vecb[i] > domain[i][1]:
                vecb[i] = domain[i][1]

            # 計算當前成本和新的成本
            cost1 = self.schedulecost(vec)
            cost2 = self.schedulecost(vecb)

            # 判斷新的解是否優於原始解 或者 演算法將以一定概率接受較差的解
            if cost2 < cost1 or random.random() < math.exp(-(cost2 - cost1) / T):
                vec = vecb

            T = T * cool  # 溫度冷卻
            print vecb[:], "代價:", self.schedulecost(vecb)

        self.printschedule(vec)
        print "模擬退火演算法得到的最小代價是:", self.schedulecost(vec)
        return vec

遺傳演算法

隨機生成一組解,成為一個種群

  • 直接遺傳 將當前種群中代價最小的一部分解,如 40% 進行直接遺傳,傳入下一代種群。
  • 變異 從題解中隨機選取一個數字,對其進行微小的,簡單的改變。
  • 交叉 選取最優解中的兩個解,將他們按照某種方式進行結合

通過上述三種方法,從上一代種群中構建出了下一代種群。而後,這一過程重複進行,知道達到了指定的迭代次數,或者連續數代都沒有改善種群,則整個過程就結束了。

# 搜尋演算法5: 遺傳演算法
# 原理: 首先隨機生成一組解,我們稱之為種群,在優化過程的每一步,演算法會計算整個種群的成本函式,
#       從而得到一個有關題解的有序列表。隨後根據種群構造進化的下一代種群,方法如下:
#       遺傳:從當前種群中選出代價最優的一部分加入下一代種群,稱為“精英選拔”
#       變異:對一個既有解進行微小的、簡單的、隨機的修改
#       交叉:選取最優解中的兩個解,按照某種方式進行交叉。方法有單點交叉,多點交叉和均勻交叉
# 一個種群是通過對最優解進行隨機的變異和配對處理構造出來的,它的大小通常與舊的種群相同,爾後,這一過程會
#       一直重複進行————新的種群經過排序,又一個種群被構造出來,如果達到指定的迭代次數之後題解都沒有得
#       改善,整個過程就結束了
# 引數:
# popsize-種群數量 step-變異改變的大小 mutprob-交叉和變異的比例 elite-直接遺傳的比例 maxiter-最大迭代次數
def geneticoptimize(self, domain, popsize=50, step=1, mutprob=0.2, elite=0.2, maxiter=100):
    # 變異操作的函式
    def mutate(vec):
        i = random.randint(0, len(domain) - 1)
        if random.random() < 0.5 and vec[i] > domain[i][0]:
            return vec[0:i] + [vec[i] - step] + vec[i + 1:]
        elif vec[i] < domain[i][1]:
            return vec[0:i] + [vec[i] + step] + vec[i + 1:]

    # 交叉操作的函式(單點交叉)
    def crossover(r1, r2):
        i = random.randint(0, len(domain) - 1)
        return r1[0:i] + r2[i:]

    # 構造初始種群
    pop = []
    for i in range(popsize):
        vec = [random.randint(domain[i][0], domain[i][1]) for i in range(len(domain))]
        pop.append(vec)

    # 每一代中有多少勝出者
    topelite = int(elite * popsize)

    # 主迴圈
    for i in range(maxiter):
        scores = [(self.schedulecost(v), v) for v in pop]
        scores.sort()
        ranked = [v for (s, v) in scores]  # 解按照代價由小到大的排序

        # 優質解遺傳到下一代
        pop = ranked[0: topelite]

        # 如果當前種群數量小於既定數量,則新增變異和交叉遺傳
        while len(pop) < popsize:
            # 隨機數小於 mutprob 則變異,否則交叉
            if random.random() < mutprob:  # mutprob控制交叉和變異的比例
                # 選擇一個個體
                c = random.randint(0, topelite)
                # 變異
                pop.append(mutate(ranked[c]))
            else:
                # 隨機選擇兩個個體進行交叉
                c1 = random.randint(0, topelite)
                c2 = random.randint(0, topelite)
                pop.append(crossover(ranked[c1], ranked[c2]))
        # 輸出當前種群中代價最小的解
        print scores[0][1], "代價:", scores[0][0]
    self.printschedule(scores[0][1])
    print "遺傳演算法求得的最小代價:", scores[0][0]
    return scores[0][1]

書中給出了關於學生宿舍選擇的一個具體例子,以下是程式碼

# -*-  coding: utf-8 -*-
__author__ = 'Bai Chenjia'

import random
import math
"""
宿舍分配問題,屬於搜尋優化問題。優化方法使用optimization.py中使用的
隨機搜尋、爬山法、模擬退火法、遺傳演算法等. 但題解的描述比之前的問題複雜
"""


class dorm:
    def __init__(self):
        # 代表宿舍,每個宿舍有兩個隔間可用
        self.dorms = ['Zeus', 'Athena', 'Hercules', 'Bacchus', 'Pluto']

        # 代表選擇,第一列代表人名,第二列和第三列代表該學生的首選和次選
        self.prefs = [('Toby', ('Bacchus', 'Hercules')),
                      ('Steve', ('Zeus', 'Pluto')),
                      ('Karen', ('Athena', 'Zeus')),
                      ('Sarah', ('Zeus', 'Pluto')),
                      ('Dave', ('Athena', 'Bacchus')),
                      ('Jeff', ('Hercules', 'Pluto')),
                      ('Fred', ('Pluto', 'Athena')),
                      ('Suzie', ('Bacchus', 'Hercules')),
                      ('Laura', ('Bacchus', 'Hercules')),
                      ('James', ('Hercules', 'Athena'))]

        # 題解的表示法:
        # 設想每個宿舍有兩個槽,本例中共有5個宿舍,則共有10個槽,我們將每名學生依序安置於各空槽
        # 內————則第一名學生有10種選擇,解的取值範圍為0-9;第二名學生有9種選擇,解的取值範圍為
        # 0-8,第三名學生解的取值範圍是0-7,以此類推,最後一名學生只有一個可選。
        # 按照上述題解的表示法初始化題解範圍:
        self.domain = [(0, 2*len(self.dorms)-1-i) for i in range(len(self.prefs))]

    # 根據題解序列vec打印出最終宿舍分配方案
    # 注意,輸出一個槽後表明該槽已經用過,需將該槽刪除
    def printsolution(self, vec):
        slots = []
        # slots = [0,0,1,1,2,2,3,3,4,4]
        for i in range(len(self.dorms)):
            slots.append(i)
            slots.append(i)
        # 迴圈題解
        print "選擇方案是:"
        for i in range(len(vec)):
            index = slots[vec[i]]
            print self.prefs[i][0], self.dorms[index]
            del slots[vec[i]]

    # 代價函式: 如果學生當前安置的宿舍使其首選則代價為0,是其次選則代價為1,否則代價為3
    # 注意,輸出一個槽後表明該槽已經用過,需將該槽刪除
    def dormcost(self, vec):
        cost = 0
        # 建立槽
        slots = []
        for i in range(len(self.dorms)):
            slots.append(i)
            slots.append(i)
        # 迴圈題解
        for i in range(len(vec)):
            index = slots[vec[i]]
            if self.dorms[index] == self.prefs[i][1][0]:
                cost += 0
            elif self.dorms[index] == self.prefs[i][1][1]:
                cost += 1
            else:
                cost += 3
            del slots[vec[i]]
        return cost

    """
    下列函式與 optimization 中函式相同,只不過代價函式和輸出函式用本問題的輸出函式
    """
    # 搜尋方法1: 隨機搜尋演算法
    # 函式會作1000次隨機猜測,記錄總代價最低的方法. domain為航班號的範圍(0-9),共有5個人,因此共有10項
    def randomoptimize(self, domain):
        best_sol = []
        bestcost = 99999
        for i in range(1000):
            sol = [0] * len(domain)
            for j in range(len(domain) / 2):  # 人數
                sol[2 * j] = random.randint(domain[2 * j][0], domain[2 * j][1])
                sol[2 * j + 1] = random.randint(domain[2 * j + 1][0], domain[2 * j + 1][1])

            print sol[:]
            newcost = self.dormcost(sol)
            if newcost < bestcost:
                bestcost = newcost
                best_sol = sol
            else:
                continue
        self.printsolution(best_sol)
        print "隨機搜尋演算法的結果的最小代價是:", bestcost
        return best_sol

    # 搜尋演算法2:爬山法
    # 首先隨機選擇一個解作為種子解,每次尋找這個種子相近的解,如果相近的解有代價更小的解,則把這個新的解作為種子
    # 依次迴圈進行,當迴圈到某種子附近的解都比該種子的代價大時,說明到達了局部極小值點,搜尋結束
    def hillclimb(self, domain):
        # 隨機產生一個航班序列作為初始種子
        seed = [random.randint(domain[i][0], domain[i][1]) for i in range(len(domain))]
        while 1:
            neighbor = []
            # 迴圈改變解的每一個值產生一個臨近解的列表
            for i in range(len(domain)):
                # 下列判斷是為了將某一位加減1後不超出domain的範圍
                # print seed
                if seed[i] > domain[i][0]:
                    newneighbor = seed[0:i] + [seed[i] - 1] + seed[i + 1:]
                    # print newneighbor[:]
                    neighbor.append(newneighbor)
                if seed[i] < domain[i][1]:
                    newneighbor = seed[0:i] + [seed[i] + 1] + seed[i + 1:]
                    # print newneighbor[:]
                    neighbor.append(newneighbor)

            # 對所有的臨近解計算代價,排序,得到代價最小的解
            neighbor_cost = sorted(
                [(s, self.dormcost(s)) for s in neighbor], key=lambda x: x[1])

            # 如果新的最小代價 > 原種子代價,則跳出迴圈
            if neighbor_cost[0][1] > self.dormcost(seed):
                break

            # 新的代價更小的臨近解作為新的種子
            seed = neighbor_cost[0][0]
            print "newseed = ", seed[:], " 代價:", self.dormcost(seed)
        # 輸出
        self.printsolution(seed)
        print "爬山法得到的解的最小代價是", self.dormcost(seed)
        return seed

    # 搜尋演算法4:模擬退火演算法
    # 引數:T代表原始溫度,cool代表冷卻率,step代表每次選擇臨近解的變化範圍
    # 原理:退火演算法以一個問題的隨機解開始,用一個變量表示溫度,這一溫度開始時非常高,而後逐步降低
    #      在每一次迭代期間,算啊會隨機選中題解中的某個數字,然後朝某個方向變化。如果新的成本值更
    #      低,則新的題解將會變成當前題解,這與爬山法類似。不過,如果成本值更高的話,則新的題解仍
    #      有可能成為當前題解,這是避免區域性極小值問題的一種嘗試。
    # 注意:演算法總會接受一個更優的解,而且在退火的開始階段會接受較差的解,隨著退火的不斷進行,演算法
    #      原來越不能接受較差的解,直到最後,它只能接受更優的解。
    # 演算法接受較差解的概率 P = exp[-(highcost-lowcost)/temperature]
    def annealingoptimize(self, domain, T=10000.0, cool=0.98, step=1):
        # 隨機初始化值
        vec = [random.randint(domain[i][0], domain[i][1]) for i in range(len(domain))]

        # 迴圈
        while T > 0.1:
            # 選擇一個索引值
            i = random.randint(0, len(domain) - 1)
            # 選擇一個改變索引值的方向
            c = random.randint(-step, step)  # -1 or 0 or 1
            # 構造新的解
            vecb = vec[:]
            vecb[i] += c
            if vecb[i] < domain[i][0]:  # 判斷越界情況
                vecb[i] = domain[i][0]
            if vecb[i] > domain[i][1]:
                vecb[i] = domain[i][1]

            # 計算當前成本和新的成本
            cost1 = self.dormcost(vec)
            cost2 = self.dormcost(vecb)

            # 判斷新的解是否優於原始解 或者 演算法將以一定概率接受較差的解
            if cost2 < cost1 or random.random() < math.exp(-(cost2 - cost1) / T):
                vec = vecb

            T = T * cool  # 溫度冷卻
            print vecb[:], "代價:", self.dormcost(vecb)

        self.printsolution(vec)
        print "模擬退火演算法得到的最小代價是:", self.dormcost(vec)
        return vec

    # 搜尋演算法5: 遺傳演算法
    # 原理: 首先隨機生成一組解,我們稱之為種群,在優化過程的每一步,演算法會計算整個種群的成本函式,
    #       從而得到一個有關題解的有序列表。隨後根據種群構造進化的下一代種群,方法如下:
    #       遺傳:從當前種群中選出代價最優的一部分加入下一代種群,稱為“精英選拔”
    #       變異:對一個既有解進行微小的、簡單的、隨機的修改
    #       交叉:選取最優解中的兩個解,按照某種方式進行交叉。方法有單點交叉,多點交叉和均勻交叉
    # 一個種群是通過對最優解進行隨機的變異和配對處理構造出來的,它的大小通常與舊的種群相同,爾後,這一過程會
    #       一直重複進行————新的種群經過排序,又一個種群被構造出來,如果達到指定的迭代次數之後題解都沒有得
    #       改善,整個過程就結束了
    # 引數:
    # popsize-種群數量 step-變異改變的大小 mutprob-交叉和變異的比例 elite-直接遺傳的比例 maxiter-最大迭代次數
    def geneticoptimize(self, domain, popsize=50, step=1, mutprob=0.2, elite=0.2, maxiter=100):
        # 變異操作的函式
        def mutate(vec):
            i = random.randint(0, len(domain) - 1)
            res = []
            if random.random() < 0.5 and vec[i] > domain[i][0]:
                res = vec[0:i] + [vec[i] - step] + vec[i + 1:]
            elif vec[i] < domain[i][1]:
                res = vec[0:i] + [vec[i] + step] + vec[i + 1:]
            else:
                res = vec
            return res

        # 交叉操作的函式(單點交叉)
        def crossover(r1, r2):
            i = random.randint(0, len(domain) - 1)
            return r1[0:i] + r2[i:]

        # 構造初始種群
        pop = []
        for i in range(popsize):
            vec = [random.randint(domain[i][0], domain[i][1]) for i in range(len(domain))]
            pop.append(vec)

        # 每一代中有多少勝出者
        topelite = int(elite * popsize)

        # 主迴圈
        for i in range(maxiter):
            if [] in pop:
                print "***"
            try:
                scores = [(self.dormcost(v), v) for v in pop]
            except:
                print "pop!!", pop[:]
            scores.sort()
            ranked = [v for (s, v) in scores]  # 解按照代價由小到大的排序

            # 優質解遺傳到下一代
            pop = ranked[0: topelite]
            # 如果當前種群數量小於既定數量,則新增變異和交叉遺傳
            while len(pop) < popsize:
                # 隨機數小於 mutprob 則變異,否則交叉
                if random.random() < mutprob:  # mutprob控制交叉和變異的比例
                    # 選擇一個個體
                    c = random.randint(0, topelite)
                    # 變異
                    if len(ranked[c]) == len(self.prefs):
                        temp = mutate(ranked[c])
                        if temp == []:
                            print "******", ranked[c]
                        else:
                            pop.append(temp)

                else:
                    # 隨機選擇兩個個體進行交叉
                    c1 = random.randint(0, topelite)
                    c2 = random.randint(0, topelite)
                    pop.append(crossover(ranked[c1], ranked[c2]))
            # 輸出當前種群中代價最小的解
            print scores[0][1], "代價:", scores[0][0]
        self.printsolution(scores[0][1])
        print "遺傳演算法求得的最小代價:", scores[0][0]
        return scores[0][1]

if __name__ == '__main__':
    dormsol = dorm()
    #sol = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    #dormsol.printsolution(sol)
    #dormsol.dormcost(sol)

    domain = dormsol.domain

    # 方法1:隨機猜測
    #dormsol.randomoptimize(domain)

    # 方法2:爬山法
    #dormsol.hillclimb(domain)

    # 方法3:模擬退火法
    #dormsol.annealingoptimize(domain)

    # 方法4:遺傳演算法
    dormsol.geneticoptimize(domain)

三種演算法分析

這三種都是用來求解函式“最大值”問題的演算法,我們可以把函式曲線理解成一個一個山峰和山谷組成的山脈(如圖片所示)。那麼我們可以設想所得到的每一個解就是一隻青蛙,我們希望它們不斷的向著更高處跳去,直到跳到最高的山峰(儘管青蛙本身不見得願意那麼做)。所以求最大值的過程就轉化成一個“青蛙跳”的過程。

下面介紹介紹“青蛙跳”的幾種方式。

爬山演算法(最速上升爬山法):

從搜尋空間中隨機產生鄰近的點,從中選擇對應解最優的個體,替換原來的個體,不斷重複上述過程。因為只對“鄰近”的點作比較,所以目光比較“短淺”,常常只能收斂到離開初始位置比較近的區域性最優解上面。對於存在很多區域性最優點的問題,通過一個簡單的迭代找出全域性最優解的機會非常渺茫。(在爬山法中,青蛙最有希望到達最靠近它出發點的山頂,但不能保證該山頂是珠穆朗瑪峰,或者是一個非常高的山峰。因為一路上它只顧上坡,沒有下坡。)

模擬退火演算法:

這個方法來自金屬熱加工過程的啟發。在金屬熱加工過程中,當金屬的溫度超過它的熔點(Melting Point)時,原子就會激烈地隨機運動。與所有的其它的物理系統相類似,原子的這種運動趨向於尋找其能量的極小狀態。在這個能量的變遷過程中,開始時。溫度非常高,使得原子具有很高的能量。隨著溫度不斷降低,金屬逐漸冷卻,金屬中的原子的能量就越來越小,最後達到所有可能的最低點。利用模擬退火演算法的時候,讓演算法從較大的跳躍開始,使到它有足夠的“能量”逃離可能“路過”的區域性最優解而不至於限制在其中,當它停在全域性最優解附近的時候,逐漸的減小跳躍量,以便使其“落腳”到全域性最優解上。(在模擬退火中,青蛙喝醉了,而且隨機地大跳躍了很長時間。運氣好的話,它從一個山峰跳過山谷,到了另外一個更高的山峰上。但最後,它漸漸清醒了並朝著它所在的峰頂跳去。)

遺傳演算法:

模擬物競天擇的生物進化過程,通過維護一個潛在解的群體執行了多方向的搜尋,並支援這些方向上的資訊構成和交換。以面為單位的搜尋,比以點為單位的搜尋,更能發現全域性最優解。(在遺傳演算法中,有很多青蛙,它們降落到喜瑪拉雅山脈的任意地方。這些青蛙並不知道它們的任務是尋找珠穆朗瑪峰。但每過幾年,就在一些海拔高度較低的地方射殺一些青蛙,並希望存活下來的青蛙是多產的,在它們所處的地方生兒育女。)可以描述成這樣的一個故事:從前,有一大群青蛙,它們被莫名其妙的零散地遺棄於喜馬拉雅山脈。於是只好在那裡艱苦的生活。海拔低的地方瀰漫著一種無色無味的毒氣,海拔越高毒氣越稀薄。可是可憐的青蛙們對此全然不覺,還是習慣於活蹦亂跳。於是,不斷有青蛙死於海拔較低的地方,而越是在海拔高的青蛙越是能活得更久,也越有機會生兒育女。就這樣經過許多年,這些青蛙們竟然都不自覺地聚攏到了一個個的山峰上,可是在所有的青蛙中,只有聚攏到珠穆朗瑪峰的青蛙被帶回了美麗的澳洲。)

作者:卡爾是正太 連結:https://www.jianshu.com/p/46d845442afb 來源:簡書 簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。