前言

遗传算法的一些思路我在开篇有提到一些,这里给出具体过程: 1、生成两个种群,分别使用BL算法和BL_plus算法; 2、开始迭代 3、调用两个种群的update_max()函数更新最优个体 4、如果两个种群中有最优解(也就是12家店铺全部铺上去了),则跳出循环,返回该个体; 5、如果达到迭代次数,则跳出循环,返回两个种群的最优个体; 6、如果达到交换迭代次数,则: 假设种群P1的最优个体适应值为fbest1,P2的最优个体适应值为fbest2 (1)若fbest1>fbest2,则用P1的最优个体替换P2的最劣个体; (2)若fbest1<fbest2,则用P2的最优个体替换P1的最劣个体; 7、对两个种群分别进行选择、交叉、变异

8、更新两个新种群的最优个体 9、若新种群最优个体的适应值小于旧种群最优个体适应值,则用旧种群的最优个体替换新种群的最劣个体。

核心代码

/// <summary>
/// 遗传算法
/// </summary>
/// <param name="path">店铺数据位置</param>
/// <param name="w">地区宽度</param>
/// <param name="h">地区高度</param>
/// <param name="iterations">迭代次数</param>
/// <param name="size">种群大小</param>
/// <param name="change">交换迭代次数</param>
/// <param name="crossover_frequency">交叉频率</param>
/// <param name="Pc1">用于计算交叉概率的参数一</param>
/// <param name="Pc2">用于计算交叉概率的参数二</param>
/// <param name="Pm1">用于计算变异概率的参数一</param>
/// <param name="Pm2">用于计算变异概率的参数二</param>
/// <param name="op_int">在基因片段一上的交叉算子</param>
/// <param name="op_bool">在基因片段二上的交叉算子</param>
/// <param name="va_int">在基因片段一上的变异算子</param>
/// <param name="va_bool">在基因片段二上的变异算子</param>
/// <returns>最优个体</returns>
public static Individual Inheritance(string path, int w, int h, int iterations, int size, int change,
    double crossover_frequency, double Pc1, double Pc2, double Pm1, double Pm2, operator_int op_int,
    operator_bool op_bool, variation_int va_int, variation_bool va_bool)
{
    Population pop1 = new Population(path, w, h, size, "BL");
    Population pop2 = new Population(path, w, h, size, "BL_plus");
    int fbest;
    for (int iteration = 0; iteration < iterations; iteration++)
    {
        pop1.update_max();
        pop2.update_max();
        fbest = pop1.fmax > pop2.fmax ? pop1.fmax : pop2.fmax;
        Console.WriteLine("第{0}次迭代,最优解的适应度为:{1}", iteration, fbest);
        if (pop1.Fmax.character.Count == 12)
        {
            return pop1.Fmax;
        }
    
        if (pop2.Fmax.character.Count == 12)
        {
            return pop2.Fmax;
        }
    
        if ((iteration + 1) % change == 0)
        {
            int min_index_1 = pop1.find_min_index();
            int min_index_2 = pop2.find_min_index();
            if (pop1.fmax > pop2.fmax)
            {
                pop2.ind[min_index_2] = pop1.Fmax;
                pop2.update_max();
            }
            else if (pop1.fmax < pop2.fmax)
            {
                pop1.ind[min_index_1] = pop2.Fmax;
                pop1.update_max();
            }
        }
    
        int crossover_times = (int) (size * crossover_frequency);
        double cros_prob, r, var_prob;
        Individual parent1, parent2;
        List<Individual> new_ind = new List<Individual>();
        List<int[]> gene_int;
        List<bool[]> gene_bool;
    
        //处理pop1
        for (int i = 0; i < crossover_times; i++)
        {
            parent1 = pop1.ind[pop1.roulette()];
            parent2 = pop1.ind[pop1.roulette()];
            cros_prob = pop1.cros_probability(parent1, parent2, Pc1, Pc2);
            r = Population.rand_double();
            if (r <= cros_prob)
            {
                gene_int = op_int(parent1.gene_order, parent2.gene_order);
                gene_bool = op_bool(parent1.gene_rotate, parent2.gene_rotate);
                Individual child;
                int[] ge_int;
                bool[] ge_bool;
                for (int j = 0; j < 2; j++)
                {
                    child = new Individual(w, h, gene_int[j], gene_bool[j], "BL",
                        pop1.decode(gene_int[j], gene_bool[j]));
                    var_prob = pop1.mut_probability(child, Pm1, Pm2);
                    r = Population.rand_double();
                    if (r < var_prob)
                    {
                        ge_int = va_int(gene_int[j]);
                        ge_bool = va_bool(gene_bool[j]);
                        child = new Individual(w, h, ge_int, ge_bool, "BL",
                            pop1.decode(ge_int, ge_bool));
                    }
    
                    new_ind.Add(child);
                }
            }
        }
    
        while (new_ind.Count < size)
        {
            new_ind.Add(pop1.ind[pop1.roulette()]);
        }
    
        int index, fmax = 0;
        for (int i = 0; i < size; i++)
        {
            if (new_ind[i].fit_count() > fmax)
            {
                fmax = new_ind[i].fit_count();
            }
        }
    
        if (fmax < pop1.fmax)
        {
            index = 0;
            int fmin = int.MaxValue;
            for (int i = 0; i < size; i++)
            {
                if (new_ind[i].fit_count() < fmin)
                {
                    index = i;
                    fmin = new_ind[i].fit_count();
                }
            }
    
            new_ind[index] = pop1.Fmax;
        }
    
        pop1.ind = new_ind;
    
        //处理pop2
        new_ind = new List<Individual>();
        for (int i = 0; i < crossover_times; i++)
        {
            parent1 = pop2.ind[pop2.roulette()];
            parent2 = pop2.ind[pop2.roulette()];
            cros_prob = pop2.cros_probability(parent1, parent2, Pc1, Pc2);
            r = Population.rand_double();
            if (r <= cros_prob)
            {
                gene_int = op_int(parent1.gene_order, parent2.gene_order);
                gene_bool = op_bool(parent1.gene_rotate, parent2.gene_rotate);
                Individual child;
                int[] ge_int;
                bool[] ge_bool;
                for (int j = 0; j < 2; j++)
                {
                    child = new Individual(w, h, gene_int[j], gene_bool[j], "BL_plus",
                        pop2.decode(gene_int[j], gene_bool[j]));
                    var_prob = pop2.mut_probability(child, Pm1, Pm2);
                    r = Population.rand_double();
                    if (r > var_prob)
                    {
                        ge_int = va_int(gene_int[j]);
                        ge_bool = va_bool(gene_bool[j]);
                        child = new Individual(w, h, ge_int, ge_bool, "BL_plus",
                            pop2.decode(ge_int, ge_bool));
                    }
    
                    new_ind.Add(child);
                }
            }
        }
    
        while (new_ind.Count < size)
        {
            new_ind.Add(pop2.ind[pop2.roulette()]);
        }
    
        fmax = 0;
        for (int i = 0; i < size; i++)
        {
            if (new_ind[i].fit_count() > fmax)
            {
                fmax = new_ind[i].fit_count();
            }
        }
    
        if (fmax < pop2.fmax)
        {
            index = 0;
            int fmin = int.MaxValue;
            for (int i = 0; i < size; i++)
            {
                if (new_ind[i].fit_count() < fmin)
                {
                    index = i;
                    fmin = new_ind[i].fit_count();
                }
            }
    
            new_ind[index] = pop2.Fmax;
        }
    
        pop2.ind = new_ind;
    }

    if (pop1.fmax > pop2.fmax)
    {
        return pop1.Fmax;
    }

    return pop2.Fmax;
}

最后

以上便是我寻找《开罗拉面店》最优解的全部过程啦!中间我走了很多弯路,甚至还准备了十几个参数准备拿来调参的,没想到才迭代了130多次就出结果了,非常幸运!不过其实也很好理解,因为按照我改进的算法生成的初始解,本来就离最优解不远,收敛速度快是很显然的。

最后贴上我找到的两个最优解: