为您推荐:
精华内容
最热下载
问答
  • 4KB mtzai 2021-01-29 03:30:18
  • 334KB weixin_38738189 2020-12-25 23:00:07
  • 2KB qq_37455590 2020-01-10 16:02:16
  • 3KB weixin_42666036 2021-10-02 09:32:10
  • 341KB weixin_38700430 2021-02-20 12:52:15
  • 743KB weixin_38636577 2020-07-25 04:10:34
  • 3KB cxk1198 2015-06-02 16:46:13
  • 算法描述:爬山算法是一种局部择优的方法,采用启发式方法,是对深度优先搜索的一种改进,它利用反馈信息帮助生成解的决策。 属于人工智能算法的一种。从当前的节点开始,和周围的邻居节点的值进行比较。 如果当前...

    算法描述:爬山算法是一种局部择优的方法,采用启发式方法,是对深度优先搜索的一种改进,它利用反馈信息帮助生成解的决策。 属于人工智能算法的一种。从当前的节点开始,和周围的邻居节点的值进行比较。 如果当前节点是最大的,那么返回当前节点,作为最大值(既山峰最高点);反之就用最高的邻居节点来,替换当前节点,从而实现向山峰的高处攀爬的目的。如此循环直到达到最高点。

    算法的优缺点:

    优点
    避免遍历,通过启发选择部分节点,从而达到提高效率的目的。
    缺点
    因为不是全面搜索,所以结果可能不是最佳。
    爬山算法一般存在以下问题:
    1)、局部最大:某个节点比周围任何一个邻居都高,但是它却不是整个问题的最高点。
    2)、高地:也称为平顶,搜索一旦到达高地,就无法确定搜索最佳方向,会产生随机走动,使得搜索效率降低。
    3)、山脊:搜索可能会在山脊的两面来回震荡,前进步伐很小。

     

     

     

    转载于:https://www.cnblogs.com/zh1Q84/p/7340474.html

    展开全文
    aochi5928 2019-10-03 04:31:04
  • 351KB weixin_38732811 2021-05-17 05:33:29
  • #爬山算法思路 #1、随机生成一个城市排序,计算该顺序下所耗总路程,并假设为最短距离 #2、设定爬山算法总代数 #3、若当前代数小于总次数,则随机交换两个城市的顺序,计算总路程,否则第5步 #4、若该次总路程小于...

    问题描述

    ​ 旅行商问题(Travelling Salesman Problem, 简记TSP,亦称货郎担问题):设有n个城市和距离矩阵D=[dij],其中dij表示城市i到城市j的距离,i,j=1,2 … n,则问题是要找出遍访每个城市恰好一次的一条回路并使其路径长度为最短。

    一、动态规划解决旅行商问题

    ​ 要使用动态规划,需要问题本身有最优子结构,我们需要找到要解决的问题的子问题。题目要求,从0(a)出发,经过[1(b),2©,3(d)]这几个城市,然后回到0,使得花费最少。要实现这个要求,需要从下面三个实现方案中选择花费最少的方案。

    ​ 从0出发,到1,然后再从1出发,经过[2,3]这几个城市,然后回到0,使得花费最少。
    ​ 从0出发,到2,然后再从2出发,经过[1,3]这几个城市,然后回到0,使得花费最少。
    ​ 从0出发,到3,然后再从3出发,经过[1,2]这几个城市,然后回到0,使得花费最少。
    ​ 可以发现,三个小的解决方案的最优解,构成了大的解决方案,所以这个问题具有最优子结构,可以用动态规划来实现。

    ​ 设置一个二维的动态规划表dp,定义符号{1,2,3}表示经过[1,2,3]这几个城市,然后回到0。
    ​ 设置一个二维数组l保存两个城市之间的距离。
    ​ 那么题目就是求dp[0][{1,2,3}]。将{1,2,3}表示成二进制,就是111,对应10进制的7,所以题目是在求dp[0][7];

    ​ 要求三个方案的最小值意味:

    ​ dp[0][{1,2,3}] = min{l[0][1]+dp[1][{2,3}] ,l[0][2]+dp[2][{1,3}] ,l[0][3]+dp[3][{1,2}]}
    ​ dp[1][{2,3}] = min{ l[1][2]+dp[2][{3}] ,l[1][3]+dp[3][{2}]}
    ​ dp[2][{3}] = l[2][3]+dp[3][{}]
    ​ dp[3][{}]就是从3出发,不经过任何城市,回到0的花费,所以dp[3][{}] = l[3][0]

    1.1 相关代码:

    #确定结点个数和权值
        def prepare(self):
            # 初始化dp和权值矩阵value
            Max = 1000
            temp = []
            tmp = []
            for i in range(Max):
                for j in range(Max):
                    temp.append(0x7ffff)
                    tmp.append(0)
                # print(temp)
                self.dp.append(copy.deepcopy(temp))
                self.value.append(copy.deepcopy(tmp))
                temp.clear()
                tmp.clear()
    
            self.value[0][1] = self.value[1][0] = 2
            self.value[0][2] = self.value[2][0] = 5
            self.value[0][3] = self.value[3][0] = 7
            self.value[1][2] = self.value[2][1] = 8
            self.value[1][3] = self.value[3][1] = 3
            self.value[2][3] = self.value[3][2] = 1
    
        #动态规划求解旅行商问题
        '''
        dp[0][{1,2,3}] = min{l[0][1]+dp[1][{2,3}] ,l[0][2]+dp[2][{1,3}] ,l[0][3]+dp[3][{1,2}]}
        dp[1][{2,3}] = min{ l[1][2]+dp[2][{3}] ,l[1][3]+dp[3][{2}]}
        dp[2][{3}] = l[2][3]+dp[3][{}] = l[2][3]+ l[3][0]
        '''
        def dp_method(self):
            #初始化dp数组第一列
            for i in range(self.n):
                self.dp[i][0] = self.value[i][0]
            col = 1<< self.n - 1
            print(col)
            for j in range(1,col):
                for i in range(self.n):
                    #i为走过的城市,如果j中包含该城市,就跳过
                    if i != 0 and j >> (i-1) & 1:
                        continue
                    '''
                    从2出发,要去{1,3}。
                    先看去1的路,去了1集合{1,3}中只剩下{3} ,{3}对应4,所以要求的dp表就是dp[1][4],这个4可以通过(101) ^ (1)得到,(1) = 1<<(1-1)
                    再看去2的路,5 = 101的第二位是0,所以不能去2。判断第二位为1,用(5>>(2-1)) &1==1。而且也由于从2出发,就更不能去了。
                    最后看去3的路,去了3集合{1,3}中只剩下{1},{1}对应这1,所以要求的dp表就是dp[3][1],1通过(101) ^ (100)得到。(100) = 1<<(3-1)
                    '''
                    for k in range(1,col):
                        #判断是否要经过k城市,不能经过就跳过
                        if j>>(k-1)&1 == 0:
                            continue
                        if self.dp[i][j] > self.value[i][k] + self.dp[k][j ^ (1 << (k-1))]:
                            self.dp[i][j] = self.value[i][k] + self.dp[k][j ^ (1 << (k - 1))]
    
    

    1.2 运行结果:

    在这里插入图片描述

    二、爬山法解决旅行商问题

    ​ 爬山算法是一种局部择优的方法,采用启发式方法,是对深度优先搜索的一种改进,它利用反馈信息帮助生成解的决策。 该算法每次从当前解的临近解空间中选择一个最优解作为当前解,直到达到一个局部最优解。属于人工智能算法的一种。

    ​ 爬山算法实现很简单,其主要缺点是会陷入局部最优解,而不一定能搜索到全局最优解。

    #爬山算法思路
    #1、随机生成一个城市排序,计算该顺序下所耗总路程,并假设为最短距离
    #2、设定爬山算法总代数
    #3、若当前代数小于总次数,则随机交换两个城市的顺序,计算总路程,否则第5步
    #4、若该次总路程小于假设的最短距离,则更新最短距离,否则继续第3步
    #5、输出此时的最短距离,和城市访问顺序
    

    2.1 相关代码:

        def prepare_for_hill_climbing_and_genetic_algorithm(self):
            #读取34个城市坐标
            #存放城市名和坐标的字典,valuse存放的是元组
            data = xlrd.open_workbook('中国省会城市坐标.xlsx')
            table = data.sheets()[0]
            row = table.nrows
            #城市数量
            self.num = row
            self.citys = {}
            self.citys_name = []
            for i in range(row):
                self.citys[table.cell_value(i,0)] = (table.cell_value(i,1),table.cell_value(i,2))
                self.citys_name.append(table.cell_value(i,0))
            #print(self.citys)
            #print(self.citys_name)
    
        #求两城市间的距离(欧氏距离)
        def distance(self,city_a,city_b):
            #dist代表距离
            x = city_a[0] - city_b[0]
            y = city_a[1] - city_b[1]
            dist = (x**2 + y**2)**0.5
            return dist
        #根据访问顺序求总距离
        def all_distance(self,citys_num):
            #sum初始化为最后一个城市到第一个城市的距离
            sum = self.distance(self.citys[self.citys_name[citys_num[0]]],self.citys[self.citys_name[citys_num[len(citys_num)-1]]])
            for i in range(len(citys_num)-1):
                citys_a = self.citys[self.citys_name[citys_num[i]]]
                citys_b = self.citys[self.citys_name[citys_num[i+1]]]
                sum += self.distance(citys_a,citys_b)
            return sum
    
        #爬山算法思路
        #1、随机生成一个城市排序,计算该顺序下所耗总路程,并假设为最短距离
        #2、设定爬山算法总代数
        #3、若当前代数小于总次数,则随机交换两个城市的顺序,计算总路程,否则第5步
        #4、若该次总路程小于假设的最短距离,则更新最短距离,否则继续第3步
        #5、输出此时的最短距离,和城市访问顺序
        def hill_climbing(self):
            #给城市编号
            citys_num = list(range(self.num))
            #打乱城市访问顺序
            shuffle(citys_num)
            #初始化最短顺序
            ans = copy.deepcopy(citys_num)
            #初始化最短顺序出现的代数
            generation = 0
            #计算总距离
            shortest_distance = self.all_distance(citys_num)
            print("初始距离:{}".format(self.all_distance(citys_num)))
            #设定总代数
            generations = 100000
            #x轴
            x = []
            x.append(0)
            #y轴
            y = []
            y.append(shortest_distance)
            a = 0
            #print(random.randint(0, 10))
            while a < generations:
                a += 1
                #随机交换两城市顺序
                c1 = random.randint(0, 10)
                c2 = random.randint(0, 10)
    
                temp = citys_num[c1]
                citys_num[c1] = citys_num[c2]
                citys_num[c2] = temp
                dist = self.all_distance(citys_num)
                if dist < shortest_distance:
                    x.append(a)
                    y.append(dist)
                    shortest_distance = dist
                    print(shortest_distance)
                    ans = copy.deepcopy(citys_num)
                    generation = a
            print("最短距离:{}".format(shortest_distance))
            print("最短访问顺序:{}".format(ans))
            print("最短访问顺序出现的代数:{}".format(generation))
            plt.title("hill_climbing")
            plt.xlabel("generations")
            plt.ylabel("distance")
            plt.plot(x, y, "ob")
            plt.show()
            #画线路图
            self.drawPic(ans)
    
        #画路线图
        def drawPic(self,citys_num):
            dots = []
            for i in range(len(citys_num)):
                temp = []
                temp.append(self.citys[self.citys_name[citys_num[i]]][0])
                temp.append(self.citys[self.citys_name[citys_num[i]]][1])
                dots.append(temp)
            temp = []
            temp.append(self.citys[self.citys_name[citys_num[0]]][0])
            temp.append(self.citys[self.citys_name[citys_num[0]]][1])
            dots.append(temp)
            plt.figure(figsize=(10, 6))
            plt.xlim(85.00000, 130, 0.002)  # x轴的刻度范围
            plt.ylim(15, 50, 0.001)  # y轴的刻度范围
            plt.xlabel('城市经度', fontproperties="simhei")  # x轴的标题
            plt.ylabel('城市纬度', fontproperties="simhei")  # y轴的标题
            # 绘制各个点及点所代表地点名称
            for i in range(len(dots) - 1):
                plt.text(dots[i][0], dots[i][1], self.citys_name[citys_num[i]], color='#0085c3', fontproperties="simhei")
                plt.plot(dots[i][0], dots[i][1], 'o', color='#0085c3')
            # 连接各个点
            for i in range(len(dots) - 1):
                start = (dots[i][0], dots[i + 1][0])
                end = (dots[i][1],dots[i + 1][1])
                plt.plot(start, end, color='#000000')
            plt.show()
    

    2.2 运行结果:

    城市数据:

    City(116.41667, 39.91667, “北京”),

    City(121.43333, 34.50000, “上海”),

    City(113.00000, 28.21667, “长沙”),

    City(106.26667, 38.46667, “银川”),

    City(109.50000, 18.20000, “三亚”),

    City(112.53333, 37.86667, “太原”),

    City(91.00000, 29.60000, “拉萨”),

    City(102.73333, 25.05000, “昆明”),

    City(126.63333, 45.75000, “哈尔滨”),

    City(113.65000, 34.76667, “郑州”),

    City(113.50000, 22.20000, “澳门”)));

    在这里插入图片描述

    三、遗传算法解决旅行商问题

    ​ 遗传算法(GeneticAlgorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,通过模拟自然进化过程搜索最优解。遗传算法是从首先是初始化一个种群,然后根据适应性函数确定个体的适应度,由适应度来选择个体进行交叉,以某种概率让个体进行变异,从而不断选出适应度高的个体,进而更新种群。

    ​ 算法流程如下所示。

    #遗传算法
        #1、确定种群规模,迭代次数,变异概率等
        #2、初始化种群(初始化城市序列)
        #3、计算个体适应度
        #4、选择个体进行交叉
        #5、选择个体进行变异
        #6、用产生的新个体更新种群
        #7、如果达到迭代次数则输出适应度最高的个体,否则回到第(3)步
        #8、结束
    

    3.1 相关代码:

    #选择
        #按照适应度从大到小排序,返回前population_size个子代
        def select(self,fitness,generation,population_size):
            original_fitness = copy.deepcopy(fitness)
            fitness.sort(reverse=True)
            new_generation = []
            for i in range(population_size):
                index = original_fitness.index(fitness[i])
                new_generation.append(copy.deepcopy(generation[index]))
            return new_generation
        #遗传算法
        #1、确定种群规模,迭代次数,变异概率等
        #2、初始化种群(初始化城市序列)
        #3、计算个体适应度
        #4、选择个体进行交叉
        #5、选择个体进行变异
        #6、用产生的新个体更新种群
        #7、如果达到迭代次数则输出适应度最高的个体,否则回到第(3)步
        #8、结束
        def genetic_algorithm(self):
            #确定种群规模,迭代次数,变异概率等
            population_size = 10
            generations = 100000
            mutation_probability = 0.01
            fitness = [] #适应度列表
            x = [] #迭代次数
            y = [] #每轮迭代中最优子代对应的距离
            coordinate = []#保留迭代的所有(x,y)
            #初始化种群(初始化城市序列)
            generation = []
            # 给城市编号
            citys_num = list(range(self.num))
            for i in range(population_size):
                # 打乱城市访问顺序
                shuffle(citys_num)
                generation.append(copy.deepcopy(citys_num))
            #print(generation)
            a = 0
            while a < generations:
                a += 1
                #计算个体适应度,将适应度存入适应度列表
                fitness.clear()
                for i in range(len(generation)):
                    fitness.append(1/self.all_distance(generation[i]))
                #输出迭代过程
                max_fitness = max(fitness)
                print(max_fitness)
                print(1/max_fitness)
                x.append(a)
                y.append(1/max_fitness)
                #将种群按照适应度从大到小排序,选取前population_size个体保留
                generation = copy.deepcopy(self.select(fitness,generation,population_size))
                # 4、选择个体进行交叉
                parent1_list = []
                parent2_list = []
                #随机选择5个父一代,其余按顺序作为父二代
                for i in range(int(population_size/2)):
                    tmp = random.randint(0, population_size - 1)
                    #如果tmp已经存在,继续随机
                    while tmp in parent1_list:
                        tmp = random.randint(0, population_size - 1)
                    parent1_list.append(tmp)
    
                for i in range(population_size):
                    if i not in parent1_list:
                        parent2_list.append(i)
                #交叉
                children = []
                index = []
                for i in range(int(population_size/2)):
                    children.clear()
                    parent1 = generation[parent1_list[i]]
                    parent2 = generation[parent2_list[i]]
                    #随机取parent1中的城市加入children,并取parent2中的其他城市,顺序加入children
                    tmp = random.randint(1,self.num)#parent1中取城市的个数
                    index.clear()
                    for j in range(tmp):
                        temp = random.randint(0, self.num - 1)
                        # 如果temp已经存在,继续随机
                        while temp in index:
                            temp = random.randint(0, self.num - 1)
                        index.append(temp)
                    #取parent1中的城市加入children
                    for j in range(len(index)):
                        children.append(parent1[index[j]])
                    #取parent2中的其他城市,顺序加入children
                    for j in range(self.num):
                        if parent2[j] not in children:
                            children.append(parent2[j])
                    #0.01的概率发生变异
                    if random.randint(1,100) == 100*mutation_probability:
                        print("发生变异")
                        print("变异前:{}".format(children))
                        # 随机交换两城市顺序
                        c1 = random.randint(0, self.num-1)
                        c2 = random.randint(0, self.num-1)
                        temp = children[c1]
                        children[c1] = children[c2]
                        children[c2] = temp
                        print("变异后:{}".format(children))
                    #把子代加入种群
                    generation.append(copy.deepcopy(children))
            # 输出最终适应度
            print("最终适应度:{}".format(max_fitness))
            print("最短距离:{}".format(1/max_fitness))
            print("最短访问顺序:{}".format(generation[0]))
            #最优子代迭代图
            plt.title("genetic_algorithm")
            plt.xlabel("generations")
            plt.ylabel("distance")
            plt.scatter(x, y, 1,)
    
            # 连接各个点
            for i in range(len(x) - 1):
                start = (x[i], x[i+1])
                end = (y[i],y[i+1])
                plt.plot(start, end, color='#000000',linewidth=0.5)
            plt.show()
            self.drawPic(generation[0])
    
        def prepare_for_hill_climbing_and_genetic_algorithm(self):
            #读取34个城市坐标
            #存放城市名和坐标的字典,valuse存放的是元组
            data = xlrd.open_workbook('中国省会城市坐标.xlsx')
            table = data.sheets()[0]
            row = table.nrows
            #城市数量
            self.num = row
            self.citys = {}
            self.citys_name = []
            for i in range(row):
                self.citys[table.cell_value(i,0)] = (table.cell_value(i,1),table.cell_value(i,2))
                self.citys_name.append(table.cell_value(i,0))
            #print(self.citys)
            #print(self.citys_name)
    
        #求两城市间的距离(欧氏距离)
        def distance(self,city_a,city_b):
            #dist代表距离
            x = city_a[0] - city_b[0]
            y = city_a[1] - city_b[1]
            dist = (x**2 + y**2)**0.5
            return dist
        
        #根据访问顺序求总距离
        def all_distance(self,citys_num):
            #sum初始化为最后一个城市到第一个城市的距离
            sum = self.distance(self.citys[self.citys_name[citys_num[0]]],self.citys[self.citys_name[citys_num[len(citys_num)-1]]])
            for i in range(len(citys_num)-1):
                citys_a = self.citys[self.citys_name[citys_num[i]]]
                citys_b = self.citys[self.citys_name[citys_num[i+1]]]
                sum += self.distance(citys_a,citys_b)
            return sum
        
        #画路线图
        def drawPic(self,citys_num):
            dots = []
            for i in range(len(citys_num)):
                temp = []
                temp.append(self.citys[self.citys_name[citys_num[i]]][0])
                temp.append(self.citys[self.citys_name[citys_num[i]]][1])
                dots.append(temp)
            temp = []
            temp.append(self.citys[self.citys_name[citys_num[0]]][0])
            temp.append(self.citys[self.citys_name[citys_num[0]]][1])
            dots.append(temp)
            plt.figure(figsize=(10, 6))
            plt.xlim(85.00000, 130, 0.002)  # x轴的刻度范围
            plt.ylim(15, 50, 0.001)  # y轴的刻度范围
            plt.xlabel('城市经度', fontproperties="simhei")  # x轴的标题
            plt.ylabel('城市纬度', fontproperties="simhei")  # y轴的标题
            # 绘制各个点及点所代表地点名称
            for i in range(len(dots) - 1):
                plt.text(dots[i][0], dots[i][1], self.citys_name[citys_num[i]], color='#0085c3', fontproperties="simhei")
                plt.plot(dots[i][0], dots[i][1], 'o', color='#0085c3')
            # 连接各个点
            for i in range(len(dots) - 1):
                start = (dots[i][0], dots[i + 1][0])
                end = (dots[i][1],dots[i + 1][1])
                plt.plot(start, end, color='#000000')
            plt.show()
    

    3.2 运行结果:

    城市数据:

    北京 116.46 39.92
    天津 117.2 39.13
    上海 121.48 31.22
    重庆 106.54 29.59
    拉萨 91.11 29.97
    乌鲁木齐 87.68 43.77
    银川 106.27 38.47
    呼和浩特 111.65 40.82
    南宁 108.33 22.84
    哈尔滨 126.63 45.75
    长春 125.35 43.88
    沈阳 123.38 41.8
    石家庄 114.48 38.03
    太原 112.53 37.87
    西宁 101.74 36.56
    济南 117 36.65
    郑州 113.6 34.76
    南京 118.78 32.04
    合肥 117.27 31.86
    杭州 120.19 30.26
    福州 119.3 26.08
    南昌 115.89 28.68
    长沙 113 28.21
    武汉 114.31 30.52
    广州 113.23 23.16
    台北 121.5 25.05
    海口 110.35 20.02
    兰州 103.73 36.03
    西安 108.95 34.27
    成都 104.06 30.67
    贵阳 106.71 26.57
    昆明 102.73 25.04
    香港 114.1 22.2
    澳门 113.33 22.13
    在这里插入图片描述

    四、总结

    ​ 动态规划求解旅行商问题在解决城市数量较少时有着非常好的效果,可以求得准确解,但是当城市数量增多,比如遗传算法解决旅行商问题中的34个城市求最短路径问题,使用动态规划就需要大量的内存空间,dp数组大小将为34*(2^34),显然这时再使用动态规划就不太现实。

    ​ 爬山算法容易陷入局部最优解,这时可以采用

    ​ 1、随机爬山法,它在上山移动中随机地选择下一步;选择的概率随上山移动的陡峭程度而变化。这种算法通常比最陡上升算法的收敛速度慢很多,但是在某些状态空间地形图上能找到更好的解。

    ​ 2、首选爬山法,它在实现随机爬山法的基础上,采用的方式是随机地生成后继结点,直到生成一个优于当前结点的后继。这个算法在有很多后继结点的情况下有很好的效果。到现在为止,我们描述的爬山法算法还是不完备的—它们经常会在目标存在的情况下因为被局部极大值卡住而找不到该目标。还有一种值得提出的方法

    ​ 3、随机重新开始的爬山法,它通过随机生成的初始状态进行一系列的爬山法搜索,找到目标时停止搜索。这个算法是完备的概率接近于1,原因是它最终会生成一个目标状态作为初始状态。

    ​ 相对于爬山算法来说,遗传算法拥有更高的效率,能够解决更多城市的旅行商问题,并且很快就能收敛,求得近似解。

    五、参考文章

    用遗传算法求解旅行商问题
    基于爬山算法求解TSP问题(JAVA)
    旅行商问题(TSP)

    六、完整代码

    请添加图片描述

    展开全文
    sgsx11 2021-11-22 22:55:10
  • 爬山算法大体思路爬山算法即是模拟爬山的过程,随机选择一个位置爬山,每次朝着更高的方向移动,直到到达山顶具体操作把当前的节点和要走的节点的值进行比较。 如果当前节点是最大的,那么不进行操作;反之就用要走...

    爬山算法

    大体思路

    爬山算法即是模拟爬山的过程,随机选择一个位置爬山,每次朝着更高的方向移动,直到到达山顶

    具体操作

    把当前的节点和要走的节点的值进行比较。 如果当前节点是最大的,那么不进行操作;反之就用要走的的节点来替换当前节点,从而实现向山峰的高处攀爬的目的。如此循环直到达到最高点。

    缺点

    会陷入局部最优解。只适用于计算几何等局部最优解集中的题目。

    #include

    #include

    using namespace std;

    #define maxn 105

    int n,go[4][2]={{1,0},{-1,0},{0,1},{0,-1}};

    double x[maxn],y[maxn],sx,sy;

    double calc(double x1,double y1){

    double ans=0;

    for(int i=0;i

    ans+=sqrt((x1-x[i])*(x1-x[i])+(y1-y[i])*(y1-y[i]));

    }

    return ans;

    }

    int main(){

    scanf("%d",&n);

    for(int i=0;i

    scanf("%lf%lf",x+i,y+i),sx+=x[i],sy+=y[i];

    }

    sx/=n,sy/=n;

    double ans=calc(sx,sy),x1,y1,k;

    for(double i=1e4;i>1e-3;i*=0.9){

    for(int i=0;i<4;i++){

    x1=sx+go[i][0]*i,y1=sy+go[i][1]*i;

    k=calc(x1,y1);

    if(k

    ans=k,sx=x1,sy=y1;

    }

    }

    }

    printf("%.0lf",ans);

    return 0;

    }

    模拟退火

    模拟退火和爬山只有一点不同:

    如果当前节点比要走的节点更优,则爬山一定不会跳到要走的节点

    但模拟退火有一定的几率会跳到要走的节点,并且这个几率越来越小

    #include

    #include

    #include

    using namespace std;

    #define maxn 50

    int n,id;

    double x[maxn],y[maxn],z[maxn];

    inline double dis(double x1,double y1,double z1,double x2,double y2,double z2){

    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));

    }

    double calc(double x1,double y1,double z1){

    double ans=dis(x1,y1,z1,x[0],y[0],z[0]),k;

    id=0;

    for(int i=1;i

    if(ans

    ans=k,id=i;

    }

    }

    return ans;

    }

    void work(){

    double sx=0,sy=0,sz=0,ans,k,x1,y1,z1;

    for(int i=0;i

    x1=sx/=n,y1=sy/=n,z1=sz/=n;

    ans=k=calc(sx,sy,sz);

    int si=0;

    for(double i=1e2;i>1e-7;i*=0.98){

    x1=sx+(x[id]-sx)/k*i;

    y1=sy+(y[id]-sy)/k*i;

    z1=sz+(z[id]-sz)/k*i;

    k=calc(x1,y1,z1);

    if(k

    if(k++si)sx=x1,sy=y1,sz=z1;//如果不比原先优,则有一定几率去走

    }

    printf("%.5lf\n",ans);

    }

    int main(){

    srand(1231435);

    while(~scanf("%d",&n)&&n)work();

    return 0;

    }

    展开全文
    weixin_27015733 2021-04-20 04:28:30
  • 4星
    15KB fengjliang2009 2012-04-21 15:32:34
  • 随机爬山是一种优化算法。它利用随机性作为搜索过程的一部分。这使得该算法适用于非线性目标函数,而其他局部搜索算法不能很好地运行。它也是一种局部搜索算法,这意味着它修改了单个解决方案并搜索搜...

    随机爬山是一种优化算法。它利用随机性作为搜索过程的一部分。这使得该算法适用于非线性目标函数,而其他局部搜索算法不能很好地运行。它也是一种局部搜索算法,这意味着它修改了单个解决方案并搜索搜索空间的相对局部区域,直到找到局部最优值为止。这意味着它适用于单峰优化问题或在应用全局优化算法后使用。

    在本教程中,您将发现用于函数优化的爬山优化算法完成本教程后,您将知道:

    • 爬山是用于功能优化的随机局部搜索算法。

    • 如何在Python中从头开始实现爬山算法。

    • 如何应用爬山算法并检查算法结果。

    教程概述

    本教程分为三个部分:他们是:

    • 爬山算法

    • 爬山算法的实现

    • 应用爬山算法的示例

    爬山算法

    随机爬山算法是一种随机局部搜索优化算法。它以起始点作为输入和步长,步长是搜索空间内的距离。该算法将初始点作为当前最佳候选解决方案,并在提供的点的步长距离内生成一个新点。计算生成的点,如果它等于或好于当前点,则将其视为当前点。新点的生成使用随机性,通常称为随机爬山。这意味着该算法可以跳过响应表面的颠簸,嘈杂,不连续或欺骗性区域,作为搜索的一部分。重要的是接受具有相等评估的不同点,因为它允许算法继续探索搜索空间,例如在响应表面的平坦区域上。限制这些所谓的“横向”移动以避免无限循环也可能是有帮助的。该过程一直持续到满足停止条件,例如最大数量的功能评估或给定数量的功能评估内没有改善为止。该算法之所以得名,是因为它会(随机地)爬到响应面的山坡上,达到局部最优值。这并不意味着它只能用于最大化目标函数。这只是一个名字。实际上,通常,我们最小化功能而不是最大化它们。作为局部搜索算法,它可能会陷入局部最优状态。然而,多次重启可以允许算法定位全局最优。步长必须足够大,以允许在搜索空间中找到更好的附近点,但步幅不能太大,以使搜索跳出包含局部最优值的区域。

    爬山算法的实现

    在撰写本文时,SciPy库未提供随机爬山的实现。但是,我们可以自己实现它。首先,我们必须定义目标函数和每个输入变量到目标函数的界限。目标函数只是一个Python函数,我们将其命名为Objective()。边界将是一个2D数组,每个输入变量都具有一个维度,该变量定义了变量的最小值和最大值。例如,一维目标函数和界限将定义如下:

    # objective function
    def objective(x):
     return 0
     
    # define range for input
    bounds = asarray([[-5.0, 5.0]])
    

    接下来,我们可以生成初始解作为问题范围内的随机点,然后使用目标函数对其进行评估。

    # generate an initial point
    solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
    # evaluate the initial point
    solution_eval = objective(solution)
    

    现在我们可以遍历定义为“ n_iterations”的算法的预定义迭代次数,例如100或1,000。

    # run the hill climb
    for i in range(n_iterations):
    

    算法迭代的第一步是采取步骤。这需要预定义的“ step_size”参数,该参数相对于搜索空间的边界。我们将采用高斯分布的随机步骤,其中均值是我们的当前点,标准偏差由“ step_size”定义。这意味着大约99%的步骤将在当前点的(3 * step_size)之内。

    # take a step
    candidate = solution + randn(len(bounds)) * step_size
    

    我们不必采取这种方式。您可能希望使用0到步长之间的均匀分布。例如:

    # take a step
    candidate = solution + rand(len(bounds)) * step_size
    

    接下来,我们需要评估具有目标函数的新候选解决方案。

    # evaluate candidate point
    candidte_eval = objective(candidate)
    

    然后,我们需要检查此新点的评估结果是否等于或优于当前最佳点,如果是,则用此新点替换当前最佳点。

    # check if we should keep the new point
    if candidte_eval <= solution_eval:
     # store the new point
     solution, solution_eval = candidate, candidte_eval
     # report progress
     print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
    

    就是这样。我们可以将此爬山算法实现为可重用函数,该函数将目标函数的名称,每个输入变量的范围,总迭代次数和步骤作为参数,并返回找到的最佳解决方案及其评估。

    # hill climbing local search algorithm
    def hillclimbing(objective, bounds, n_iterations, step_size):
     # generate an initial point
     solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
     # evaluate the initial point
     solution_eval = objective(solution)
     # run the hill climb
     for i in range(n_iterations):
      # take a step
      candidate = solution + randn(len(bounds)) * step_size
      # evaluate candidate point
      candidte_eval = objective(candidate)
      # check if we should keep the new point
      if candidte_eval <= solution_eval:
       # store the new point
       solution, solution_eval = candidate, candidte_eval
       # report progress
       print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
     return [solution, solution_eval]
    

    现在,我们知道了如何在Python中实现爬山算法,让我们看看如何使用它来优化目标函数。

    应用爬山算法的示例

    在本节中,我们将把爬山优化算法应用于目标函数。首先,让我们定义目标函数。我们将使用一个简单的一维x ^ 2目标函数,其边界为[-5,5]。下面的示例定义了函数,然后为输入值的网格创建了函数响应面的折线图,并用红线标记了f(0.0)= 0.0处的最佳值。

    # convex unimodal optimization function
    from numpy import arange
    from matplotlib import pyplot
     
    # objective function
    def objective(x):
     return x[0]**2.0
     
    # define range for input
    r_min, r_max = -5.0, 5.0
    # sample input range uniformly at 0.1 increments
    inputs = arange(r_min, r_max, 0.1)
    # compute targets
    results = [objective([x]) for x in inputs]
    # create a line plot of input vs result
    pyplot.plot(inputs, results)
    # define optimal input value
    x_optima = 0.0
    # draw a vertical line at the optimal input
    pyplot.axvline(x=x_optima, ls='--', color='red')
    # show the plot
    pyplot.show()
    

    运行示例将创建目标函数的折线图,并清晰地标记函数的最优值。

    接下来,我们可以将爬山算法应用于目标函数。首先,我们将播种伪随机数生成器。通常这不是必需的,但是在这种情况下,我想确保每次运行算法时都得到相同的结果(相同的随机数序列),以便以后可以绘制结果。

    # seed the pseudorandom number generator
    seed(5)
    

    接下来,我们可以定义搜索的配置。在这种情况下,我们将搜索算法的1,000次迭代,并使用0.1的步长。假设我们使用的是高斯函数来生成步长,这意味着大约99%的所有步长将位于给定点(0.1 * 3)的距离内,例如 三个标准差。

    n_iterations = 1000
    # define the maximum step size
    step_size = 0.1
    

    接下来,我们可以执行搜索并报告结果。

    # perform the hill climbing search
    best, score = hillclimbing(objective, bounds, n_iterations, step_size)
    print('Done!')
    print('f(%s) = %f' % (best, score))
    

    结合在一起,下面列出了完整的示例。

    # hill climbing search of a one-dimensional objective function
    from numpy import asarray
    from numpy.random import randn
    from numpy.random import rand
    from numpy.random import seed
     
    # objective function
    def objective(x):
     return x[0]**2.0
     
    # hill climbing local search algorithm
    def hillclimbing(objective, bounds, n_iterations, step_size):
     # generate an initial point
     solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
     # evaluate the initial point
     solution_eval = objective(solution)
     # run the hill climb
     for i in range(n_iterations):
      # take a step
      candidate = solution + randn(len(bounds)) * step_size
      # evaluate candidate point
      candidte_eval = objective(candidate)
      # check if we should keep the new point
      if candidte_eval <= solution_eval:
       # store the new point
       solution, solution_eval = candidate, candidte_eval
       # report progress
       print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
     return [solution, solution_eval]
     
    # seed the pseudorandom number generator
    seed(5)
    # define range for input
    bounds = asarray([[-5.0, 5.0]])
    # define the total iterations
    n_iterations = 1000
    # define the maximum step size
    step_size = 0.1
    # perform the hill climbing search
    best, score = hillclimbing(objective, bounds, n_iterations, step_size)
    print('Done!')
    print('f(%s) = %f' % (best, score))
    

    运行该示例将报告搜索进度,包括每次检测到改进时的迭代次数,该函数的输入以及来自目标函数的响应。搜索结束时,找到最佳解决方案,并报告其评估结果。在这种情况下,我们可以看到在算法的1,000次迭代中有36处改进,并且该解决方案非常接近于0.0的最佳输入,其计算结果为f(0.0)= 0.0。

    >1 f([-2.74290923]) = 7.52355
    >3 f([-2.65873147]) = 7.06885
    >4 f([-2.52197291]) = 6.36035
    >5 f([-2.46450214]) = 6.07377
    >7 f([-2.44740961]) = 5.98981
    >9 f([-2.28364676]) = 5.21504
    >12 f([-2.19245939]) = 4.80688
    >14 f([-2.01001538]) = 4.04016
    >15 f([-1.86425287]) = 3.47544
    >22 f([-1.79913002]) = 3.23687
    >24 f([-1.57525573]) = 2.48143
    >25 f([-1.55047719]) = 2.40398
    >26 f([-1.51783757]) = 2.30383
    >27 f([-1.49118756]) = 2.22364
    >28 f([-1.45344116]) = 2.11249
    >30 f([-1.33055275]) = 1.77037
    >32 f([-1.17805016]) = 1.38780
    >33 f([-1.15189314]) = 1.32686
    >36 f([-1.03852644]) = 1.07854
    >37 f([-0.99135322]) = 0.98278
    >38 f([-0.79448984]) = 0.63121
    >39 f([-0.69837955]) = 0.48773
    >42 f([-0.69317313]) = 0.48049
    >46 f([-0.61801423]) = 0.38194
    >48 f([-0.48799625]) = 0.23814
    >50 f([-0.22149135]) = 0.04906
    >54 f([-0.20017144]) = 0.04007
    >57 f([-0.15994446]) = 0.02558
    >60 f([-0.15492485]) = 0.02400
    >61 f([-0.03572481]) = 0.00128
    >64 f([-0.03051261]) = 0.00093
    >66 f([-0.0074283]) = 0.00006
    >78 f([-0.00202357]) = 0.00000
    >119 f([0.00128373]) = 0.00000
    >120 f([-0.00040911]) = 0.00000
    >314 f([-0.00017051]) = 0.00000
    Done!
    f([-0.00017051]) = 0.000000
    

    以线图的形式查看搜索的进度可能很有趣,该线图显示了每次改进后最佳解决方案的评估变化。每当有改进时,我们就可以更新hillclimbing()来跟踪目标函数的评估,并返回此分数列表。

    # hill climbing local search algorithm
    def hillclimbing(objective, bounds, n_iterations, step_size):
     # generate an initial point
     solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
     # evaluate the initial point
     solution_eval = objective(solution)
     # run the hill climb
     scores = list()
     scores.append(solution_eval)
     for i in range(n_iterations):
      # take a step
      candidate = solution + randn(len(bounds)) * step_size
      # evaluate candidate point
      candidte_eval = objective(candidate)
      # check if we should keep the new point
      if candidte_eval <= solution_eval:
       # store the new point
       solution, solution_eval = candidate, candidte_eval
       # keep track of scores
       scores.append(solution_eval)
       # report progress
       print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
     return [solution, solution_eval, scores]
    

    然后,我们可以创建这些分数的折线图,以查看搜索过程中发现的每个改进的目标函数的相对变化。

    # line plot of best scores
    pyplot.plot(scores, '.-')
    pyplot.xlabel('Improvement Number')
    pyplot.ylabel('Evaluation f(x)')
    pyplot.show()
    

    结合在一起,下面列出了执行搜索并绘制搜索过程中改进解决方案的目标函数得分的完整示例。

    # hill climbing search of a one-dimensional objective function
    from numpy import asarray
    from numpy.random import randn
    from numpy.random import rand
    from numpy.random import seed
    from matplotlib import pyplot
     
    # objective function
    def objective(x):
     return x[0]**2.0
     
    # hill climbing local search algorithm
    def hillclimbing(objective, bounds, n_iterations, step_size):
     # generate an initial point
     solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
     # evaluate the initial point
     solution_eval = objective(solution)
     # run the hill climb
     scores = list()
     scores.append(solution_eval)
     for i in range(n_iterations):
      # take a step
      candidate = solution + randn(len(bounds)) * step_size
      # evaluate candidate point
      candidte_eval = objective(candidate)
      # check if we should keep the new point
      if candidte_eval <= solution_eval:
       # store the new point
       solution, solution_eval = candidate, candidte_eval
       # keep track of scores
       scores.append(solution_eval)
       # report progress
       print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
     return [solution, solution_eval, scores]
     
    # seed the pseudorandom number generator
    seed(5)
    # define range for input
    bounds = asarray([[-5.0, 5.0]])
    # define the total iterations
    n_iterations = 1000
    # define the maximum step size
    step_size = 0.1
    # perform the hill climbing search
    best, score, scores = hillclimbing(objective, bounds, n_iterations, step_size)
    print('Done!')
    print('f(%s) = %f' % (best, score))
    # line plot of best scores
    pyplot.plot(scores, '.-')
    pyplot.xlabel('Improvement Number')
    pyplot.ylabel('Evaluation f(x)')
    pyplot.show()
    

    运行示例将执行搜索,并像以前一样报告结果。创建一个线形图,显示在爬山搜索期间每个改进的目标函数评估。在搜索过程中,我们可以看到目标函数评估发生了约36个变化,随着算法收敛到最优值,初始变化较大,而在搜索结束时变化很小,难以察觉。

    鉴于目标函数是一维的,因此可以像上面那样直接绘制响应面。通过将在搜索过程中找到的最佳候选解决方案绘制为响应面中的点,来回顾搜索的进度可能会很有趣。我们期望沿着响应面到达最优点的一系列点。这可以通过首先更新hillclimbing()函数以跟踪每个最佳候选解决方案在搜索过程中的位置来实现,然后返回最佳解决方案列表来实现。

    # hill climbing local search algorithm
    def hillclimbing(objective, bounds, n_iterations, step_size):
     # generate an initial point
     solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
     # evaluate the initial point
     solution_eval = objective(solution)
     # run the hill climb
     solutions = list()
     solutions.append(solution)
     for i in range(n_iterations):
      # take a step
      candidate = solution + randn(len(bounds)) * step_size
      # evaluate candidate point
      candidte_eval = objective(candidate)
      # check if we should keep the new point
      if candidte_eval <= solution_eval:
       # store the new point
       solution, solution_eval = candidate, candidte_eval
       # keep track of solutions
       solutions.append(solution)
       # report progress
       print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
     return [solution, solution_eval, solutions]
    

    然后,我们可以创建目标函数响应面的图,并像以前那样标记最优值。

    # sample input range uniformly at 0.1 increments
    inputs = arange(bounds[0,0], bounds[0,1], 0.1)
    # create a line plot of input vs result
    pyplot.plot(inputs, [objective([x]) for x in inputs], '--')
    # draw a vertical line at the optimal input
    pyplot.axvline(x=[0.0], ls='--', color='red')
    

    最后,我们可以将搜索找到的候选解的序列绘制成黑点。

    # plot the sample as black circles
    pyplot.plot(solutions, [objective(x) for x in solutions], 'o', color='black')
    

    结合在一起,下面列出了在目标函数的响应面上绘制改进解序列的完整示例。

    # hill climbing search of a one-dimensional objective function
    from numpy import asarray
    from numpy import arange
    from numpy.random import randn
    from numpy.random import rand
    from numpy.random import seed
    from matplotlib import pyplot
     
    # objective function
    def objective(x):
     return x[0]**2.0
     
    # hill climbing local search algorithm
    def hillclimbing(objective, bounds, n_iterations, step_size):
     # generate an initial point
     solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
     # evaluate the initial point
     solution_eval = objective(solution)
     # run the hill climb
     solutions = list()
     solutions.append(solution)
     for i in range(n_iterations):
      # take a step
      candidate = solution + randn(len(bounds)) * step_size
      # evaluate candidate point
      candidte_eval = objective(candidate)
      # check if we should keep the new point
      if candidte_eval <= solution_eval:
       # store the new point
       solution, solution_eval = candidate, candidte_eval
       # keep track of solutions
       solutions.append(solution)
       # report progress
       print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
     return [solution, solution_eval, solutions]
     
    # seed the pseudorandom number generator
    seed(5)
    # define range for input
    bounds = asarray([[-5.0, 5.0]])
    # define the total iterations
    n_iterations = 1000
    # define the maximum step size
    step_size = 0.1
    # perform the hill climbing search
    best, score, solutions = hillclimbing(objective, bounds, n_iterations, step_size)
    print('Done!')
    print('f(%s) = %f' % (best, score))
    # sample input range uniformly at 0.1 increments
    inputs = arange(bounds[0,0], bounds[0,1], 0.1)
    # create a line plot of input vs result
    pyplot.plot(inputs, [objective([x]) for x in inputs], '--')
    # draw a vertical line at the optimal input
    pyplot.axvline(x=[0.0], ls='--', color='red')
    # plot the sample as black circles
    pyplot.plot(solutions, [objective(x) for x in solutions], 'o', color='black')
    pyplot.show()
    

    运行示例将执行爬山搜索,并像以前一样报告结果。像以前一样创建一个响应面图,显示函数的熟悉的碗形,并用垂直的红线标记函数的最佳状态。在搜索过程中找到的最佳解决方案的顺序显示为黑点,沿着碗形延伸到最佳状态。

    作者:沂水寒城,CSDN博客专家,个人研究方向:机器学习、深度学习、NLP、CV

    Blog: http://yishuihancheng.blog.csdn.net

    赞 赏 作 者

    更多阅读

    2020 年最佳流行 Python 库 Top 10

    2020 Python中文社区热门文章 Top 10

    5分钟快速掌握 Python 定时任务框架

    特别推荐


    点击下方阅读原文加入社区会员

    展开全文
    BF02jgtRS00XKtCx 2021-01-29 08:32:00
  • 439KB weixin_39841848 2019-08-18 09:48:28
  • weixin_26632369 2020-07-19 13:04:55
  • weixin_39957805 2021-04-20 08:43:39
  • m0_37579232 2018-12-17 21:54:22
  • Big_SHOe 2021-11-08 23:21:50
  • weixin_29706351 2021-05-26 03:21:04
  • qq_53198408 2021-07-11 20:31:41
  • weixin_39965514 2021-05-24 04:50:25

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,956
精华内容 2,382
关键字:

爬山算法