2021-06-10

局部搜索算法是一种简单的贪心搜索算法,是解决最优化问题的一种启发式算法,该算法每次从当前解的临近解空间中根据启发函数选择一个最优解(也不一定是最优解)作为当前解,直到达到一个局部最优解。本文以求解八皇后问题来描述爬山法,模拟退火法以及遗传算法。

 

目录

 

一、 爬山法

1. 算法描述

2. 算法实现

(1)获得某一状态的h(相互攻击的皇后对的数目)

 (2)获取最优邻居

(3)完整代码

3. 实验结果

(1)实验失败

(2)实验成功

二、 模拟退火法

1. 算法描述

2. 算法实现

(1)全部代码

3. 实验结果

(1)试验失败截图

(2)实验成功截图

三、 遗传算法

1. 算法描述

2. 算法实现

(1)get_num_of_no_conflict(status)

(2)get_parent(all_status, no_conflict_num)

(3)variation(all_status)

(4)inheritance(all_status)

(5)完整代码

3. 实验结果


一、 爬山法

1. 算法描述

爬山法是一个向值增加的方向持续移动的简单循环过程--类似于登高,它将会在到达一个“峰顶”时终止,此时相邻状态中没有比它更高的值。算法不会维护搜索树,因此当前节点的数据结构只需要记录当前状态和它的目标函数值。以八皇后问题来说明爬山法,先在棋盘上每一列随机放置一个皇后,之后根据启发式评估函数h(相互攻击的皇后对的数目),只选择h最小的(即相互攻击的皇后对的数目最少)的邻居状态直到找到解或者无解,这种算法很容易改善一个坏的状态,但也有可能会陷入困境,比如邻居状态的h都不比当前小。

2. 算法实现

(1)获得某一状态的h(相互攻击的皇后对的数目)

输入一个状态,通过判断行和列的关系计算出相互攻击的皇后对的数目,并返回该数目

  1. def num_of_conflict(status): # 获取该状态下互相攻击的皇后对数
  2. num_of_conflict = 0;
  3. for col1 in range(0, 7):
  4. for col2 in range(col1+1, 8):
  5. if (status[col1] == status[col2]) \
  6. or ((col2 - col1) == abs(status[col1] - status[col2])) : #判断是否相互攻击
  7. num_of_conflict += 1;
  8. return num_of_conflict

 (2)获取最优邻居

输入当前状态,获得当前状态下的邻居状态中最好的状态,并返回该状态,如果当前状态已是最优。返回当前状态。

  1. def get_min_num_of_conflict_status(status): #返回该状态status时的最优邻居状态,如不存在,则返回本身
  2. min_status = status
  3. for col in range(0,8): #此处两个循环为遍历56种邻居
  4. for row in range(0, 8):
  5. new_status = status[:]
  6. if status[col] != row: #相等时跳过,此时是皇后位置
  7. new_status[col] = row
  8. if num_of_conflict(new_status) < num_of_conflict(min_status):
  9. min_status = new_status #new_status的相互攻击皇后数小于min_status,所以更min_status
  10. elif num_of_conflict(new_status) == num_of_conflict(min_status) \
  11. and num_of_conflict(new_status) != num_of_conflict(status):
  12. choose = random.randint(0, 1)
  13. if choose == 1: #当新状态的h也是最小时,根据概率(0,1)随机决定刷新
  14. min_status = new_status
  15. return min_status

(3)完整代码

  1. #爬山法
  2. import random
  3. def num_of_conflict(status): # 获取该状态下互相攻击的皇后对数
  4. num_of_conflict = 0;
  5. for col1 in range(0, 7):
  6. for col2 in range(col1+1, 8):
  7. if (status[col1] == status[col2]) \
  8. or ((col2 - col1) == abs(status[col1] - status[col2])) : #判断是否相互攻击
  9. num_of_conflict += 1;
  10. return num_of_conflict
  11. def get_min_num_of_conflict_status(status): #返回该状态status时的最优邻居状态,如不存在,则返回本身
  12. min_status = status
  13. for col in range(0,8): #此处两个循环为遍历56种邻居
  14. for row in range(0, 8):
  15. new_status = status[:]
  16. if status[col] != row: #相等时跳过,此时是皇后位置
  17. new_status[col] = row
  18. if num_of_conflict(new_status) < num_of_conflict(min_status):
  19. min_status = new_status #new_status的相互攻击皇后数小于min_status,所以更min_status
  20. elif num_of_conflict(new_status) == num_of_conflict(min_status) \
  21. and num_of_conflict(new_status) != num_of_conflict(status):
  22. choose = random.randint(0, 1)
  23. if choose == 1: #当新状态的h也是最小时,根据概率(0,1)随机决定刷新
  24. min_status = new_status
  25. return min_status
  26. status = [0, 0, 0, 0, 0, 0, 0, 0]
  27. for col in range(0, 8): #生成随机八皇后棋盘
  28. row = random.randint(0, 7)
  29. status[col] = row
  30. print("the initial status: ")
  31. print(status)
  32. print("the num of conflict: ")
  33. print(num_of_conflict(status))
  34. while num_of_conflict(status) > 0 : #当不为解时
  35. new_status = get_min_num_of_conflict_status(status) #获得当前状态的最优邻居
  36. if new_status == status: #最优邻居就是自己,证明h已经是最小了
  37. print("the new status: ")
  38. print(status)
  39. print("the num of conflict: ")
  40. print(num_of_conflict(status))
  41. print("can't find a answer!")
  42. break
  43. status = new_status
  44. print("the new status: ")
  45. print(status)
  46. print("the num of conflict: ")
  47. print(num_of_conflict(status))
  48. if num_of_conflict(status) == 0:
  49. print("find a answer!")

3. 实验结果

(1)实验失败

观察到最后两次h均为1,证明无法找到更优解,此时已经是局部最优,搜索失败

(2)实验成功

 


二、 模拟退火法

1. 算法描述

模拟退火算法的内层循环与爬山法类似,只是它没有选择最佳移动,而是随机移动。如果该移动使情况改善,该移动则被接收。否则,算法以某个小于1的概率接收该移动。如果移动导致状态“变坏”,概率则成指数级下降——评估值△E变坏。这个概率也随“温度”T降低而下降:开始T高的时候可能允许“坏的”移动,T越低则越不可能发生。如果调度让T下降得足够慢,算法找到最优解的概率逼近于1。以八皇后问题说明模拟退火法,随机选取56(7*8)个邻居状态中的一个,如果邻居状态的h(相互攻击的八皇后对数)小于或等于当前状态的h,则选择该邻居状态,反之,即邻居状态更差,则以一定概率(概率不断减少直到接近0时结束程序)选择该邻居状态,但T下降的足够慢,即概率下降足够慢,次数足够多,找到最优解的概率接近1。

2. 算法实现

(1)全部代码

  1. #模拟退火法
  2. import random
  3. import math
  4. def num_of_conflict(status): # 获取该状态下互相攻击的皇后对数
  5. num_of_conflict = 0;
  6. for col1 in range(0, 7):
  7. for col2 in range(col1+1, 8):
  8. if (status[col1] == status[col2]) \
  9. or ((col2 - col1) == abs(status[col1] - status[col2])) : #判断是否相互攻击
  10. num_of_conflict += 1;
  11. return num_of_conflict
  12. def get_next_num_of_conflict_status(status, T): #根据递减的T和当前状态返回一个新状态
  13. next_status = []
  14. for col in range(0,8):
  15. for row in range(0, 8):
  16. new_status = status[:]
  17. if status[col] != row:
  18. new_status[col] = row
  19. next_status.append(new_status)
  20. choose_status = random.randint(0, 55) #从56的邻居任选一个
  21. if num_of_conflict(next_status[choose_status]) <= num_of_conflict(status): #新的状态优于原先的
  22. return next_status[choose_status]
  23. else: #原先的状态优于新状态
  24. E = num_of_conflict(status) - num_of_conflict(next_status[choose_status])
  25. probability = math.e**(E/T) #概率计算公式
  26. choose = random.randint(0, 1000)/1000
  27. if choose <= probability: #以一定概率使新的状态取代原先的状态
  28. return next_status[choose_status]
  29. return status #返回原状态,不移动
  30. status = [0, 0, 0, 0, 0, 0, 0, 0]
  31. for col in range(0, 8):
  32. row = random.randint(0, 7)
  33. status[col] = row
  34. print("the initial status: ")
  35. print(status)
  36. print("the num of conflict: ")
  37. print(num_of_conflict(status))
  38. T = 5.0 #初始T,(温度)
  39. while num_of_conflict(status) > 0 : #找不到最优解
  40. new_status = get_next_num_of_conflict_status(status, T) #获取新状态
  41. if new_status == status: #不移动
  42. print("E < 0, but no move")
  43. else:
  44. status = new_status
  45. print("the new status: ")
  46. print(status)
  47. print("the num of conflict: ")
  48. print(num_of_conflict(status))
  49. if num_of_conflict(status) == 0:
  50. print("find a answer!")
  51. T = T * 0.99 # T递减,概率也递减
  52. if T < 0.0001: #运行 1077 次,此时认为T接近0
  53. print("T = 0, can't find a answer")
  54. break

3. 实验结果

(1)试验失败截图

因为T的设置问题,总共运行次数达到1077次,若T == 0, 即T无限小,认为搜索失败,但失败几率比爬山法小很多

(2)实验成功截图


三、 遗传算法

1. 算法描述

遗传算法是模拟达尔文进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法,是随机束搜索的一个变形,通过将两个父状态结合来生成后续。以八皇后问题来说明遗传算法,随机生成K个状态,以一定概率(不相互攻击的皇后对数越多,概率越大)选择两个状态,通过交换前N(0 < N < 8)个位置获得两个新的后代,同时将K个后代继续配对。配对过程可能产生变异,此时实验设置变异概率为10%。K在本次实验设为4.

2. 算法实现

(1)get_num_of_no_conflict(status)

获取不相互攻击的皇后对数

(2)get_parent(all_status, no_conflict_num)

根据特定概率从种群中返回一个父亲

(3)variation(all_status)

变异函数,变异是按照10%的几率进行的,因为存在变异,所以只要运行时间足够长(即杂交代数多),总能找到一个解

(4)inheritance(all_status)

杂交函数,输入为一个种群,输出为一个新种群

(5)完整代码

  1. #遗传算法
  2. import random
  3. def get_num_of_no_conflict(status): # 获取该状态下不互相攻击的皇后对数
  4. num_of_conflict = 0;
  5. for col1 in range(0, 7):
  6. for col2 in range(col1+1, 8):
  7. if (status[col1] == status[col2]) \
  8. or ((col2 - col1) == abs(status[col1] - status[col2])) : #判断是否相互攻击
  9. num_of_conflict += 1;
  10. return 28 - num_of_conflict #此处是求不相互攻击的
  11. def get_parent(all_status, no_conflict_num): #按照比例求状态群的某一个状态作为父亲之一
  12. choose_parent = random.randint(0, sum(no_conflict_num) - 1)
  13. if choose_parent < no_conflict_num[0]:
  14. return all_status[0]
  15. elif choose_parent >= no_conflict_num[0] and choose_parent < (no_conflict_num[0] + no_conflict_num[1]):
  16. return all_status[1]
  17. elif choose_parent >= (no_conflict_num[0] + no_conflict_num[1]) \
  18. and choose_parent < (no_conflict_num[0] + no_conflict_num[1] + no_conflict_num[2]):
  19. return all_status[2]
  20. return all_status[3]
  21. def variation(all_status): #变异
  22. for i in range(0, 4):
  23. col = random.randint(0, 7)
  24. row = random.randint(0, 7)
  25. all_status[i][col] = row
  26. return all_status
  27. def inheritance(all_status): #杂交
  28. no_conflict_num = []
  29. new_all_status = []
  30. for i in range(0, 4):
  31. no_conflict_num.append(get_num_of_no_conflict(all_status[i]))
  32. for t in range(0, 2): #一次生成两个子代,循环两次
  33. father = get_parent(all_status, no_conflict_num);
  34. mother = get_parent(all_status, no_conflict_num);
  35. while father == mother:
  36. mother = get_parent(all_status, no_conflict_num);
  37. first_child = father[:]
  38. second_child = mother[:]
  39. num = random.randint(0, 6) #各种交换下标0-num的数,形成子代
  40. for i in range(0, num+1):
  41. first_child[i] = second_child[i]
  42. second_child[i] = father[i]
  43. new_all_status.append(first_child)
  44. new_all_status.append(second_child)
  45. return new_all_status #返回新的状态种族
  46. def find_answer(all_status): #判断该状态种族是否有解
  47. for i in range(0, 4):
  48. if get_num_of_no_conflict(all_status[i]) == 28:
  49. print("find a answer:")
  50. print(all_status[i])
  51. return True
  52. return False
  53. all_status = []
  54. for i in range(0, 4): #随机生成4个状态,即种族
  55. status = [0, 0, 0, 0, 0, 0, 0, 0]
  56. for col in range(0, 8):
  57. row = random.randint(0, 7)
  58. status[col] = row
  59. all_status.append(status)
  60. print("the initial all_status: ")
  61. print(all_status)
  62. all_status = inheritance(all_status) #杂交
  63. while find_answer(all_status) == False: #找不到最优后代(最优解)则一直繁衍
  64. whether_variation = random.randint(1, 10) #10%变异的几率
  65. if whether_variation == 1:
  66. print("have a variation,and the all_status:")
  67. all_status = variation(all_status)
  68. print(all_status)
  69. else:
  70. all_status = inheritance(all_status) #杂交
  71. print("the next all_status: ")
  72. print(all_status)

 

3. 实验结果

前面已讲过,只要杂交代数足够多,且存在变异,总能找到一个解的

杂交过程

找到最优解

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/549231.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET(C#) Internals: 以一个数组填充的例子初步了解.NET 4.0中的并行(二)

引言 随着CPU多核的普及&#xff0c;编程时充分利用这个特性越显重要。上篇首先用传统的嵌套循环进行数组填充&#xff0c;然后用.NET 4.0中的System.Threading.Tasks提供的Parallel Class来并行地进行填充&#xff0c;最后对比他们的性能。本文将深入分析Parallel Class并借机…

.net框架读书笔记---CLR内存管理\垃圾收集(二)

前几天学习了CLR垃圾收集原理和基本算法&#xff0c;但是那些是仅仅相对于托管堆而言的&#xff0c;任何非托管资源的类型&#xff0c;例如文件、网络资源等&#xff0c;都必须支持一种称为终止化&#xff08;finalization&#xff09;的操作。 终止化 终止化操作允许一种资源在…

重构手法——提炼函数、搬移函数、以多态取代条件表达式

目录我的心路历程我的学习概括Extract Method&#xff08;提炼函数&#xff09;动机*--做法动机--做法*Move Method&#xff08;搬移函数&#xff09;动机*--做法动机--做法*Replace Conditional with Polymorphism&#xff08;以多态取代条件表达式&#xff09;动机*--做法动机…

FTP服务器架设详细图解

FTP是File Transfer Protocol&#xff08;文件传输协议&#xff09;的缩写&#xff0c;用来在两台计算机之间互相传送文件。FTP服务作为Internet最古老的服务之一&#xff0c;无论在过去还是现在都有着不可替代的作用。在企业中&#xff0c;对于一些大文件的共享&#xff0c;通…

IP-tools

IP-tools 网管员的第三只眼^ Ip-tools是一款功能齐全的网管软件&#xff0c;可以随时随地的向网管员报告网络的运行情况ip-tools自身集成多种tcp/ip使用工具&#xff0c;如本地信息、链接信息、端口扫描、ping、WHOIS、finger、nslookup、telnet、NetBIOS等功能。界面是全英的&…

用git提交代码到远程仓库遇到的问题

目录我的学习过程git环境配置&#xff08;Mac版&#xff09;git原理图git的push操作思路遇到的问题我的学习过程 昨天重写了一遍聊天程序&#xff0c;准备提交到git上进行代码管理。结果遇到了不少问题。我照着网上的教程进行操作&#xff0c;一步一步踩了很多坑。 git环境配…

git pull和push整理和归纳

目录各个模块概念工作区版本库暂存区远程仓库pull和push流程相关的命令暂存区相关版本库相关远程仓库相关利用远程仓库协作开发各个模块概念 我的理解&#xff1a; Git是版本管理工具&#xff0c;它主要对指定目录下的一些特定的文件的修改进行版本管理。 相关的模块有&#x…

Linux中点号,星号,加号,问号实战

目录Linux中的星号&#xff0c;点号和加号概念我的学习过程&#xff1a;我的思考过程&#xff1a;点号&#xff08;.&#xff09;星号&#xff08;*&#xff09;加号&#xff08;&#xff09;问号&#xff08;?&#xff09;linux星号&#xff0c;点号&#xff0c;加号&#xf…

广播地址的计算方法(与运算、或运算)

目录我的学习过程Python中逻辑运算符notandor位运算符取反&#xff08;~&#xff09;与&#xff08;&&#xff09;或&#xff08;|&#xff09;广播地址计算方法IP地址子网掩码网络地址广播地址广播地址计算举例我的学习过程 今天学习UDP的单播、多播、广播中&#xff0c;…

Wt::WTreeNode

2019独角兽企业重金招聘Python工程师标准>>> A single node in a tree. 〔 这个 widget 渲染的是一棵树的一个节点。〕 A tree list is constructed by combining several tree node objects in a tree hierarchy, by passing the parent tree node as the last arg…

匿名内部类探究——它是一个实例

目录我的学习过程匿名内部类概述匿名内部类探究代码验证&#xff08;匿名内部类是一个实例&#xff09;结论我的学习过程 昨天想学习一下Java8新特性&#xff0c;看到Lambda表达式可以替代匿名内部类。我对匿名内部类不太理解&#xff0c;决定学习一下。并进行了下面的归纳和思…

Lambda表达式及应用

目录Lambda表达式概念应用在forEach()方法使用用来替代匿名内部类代码验证&#xff08;Lambda表达式替代匿名内部类&#xff09;Lambda表达式 概念 语法形式&#xff1a; () -> {} 组成&#xff1a; 括号&#xff1a;表示参数列表&#xff1b;箭头&#xff1a;表示lambda…

网络地址和广播地址的快速计算方法

目录前提条件方法原理网络地址快速计算示例广播地址快速计算示例前提条件 由IP地址和子网掩码&#xff0c;快速计算网络地址和广播地址。 小窍门前提&#xff1a;当子网掩码组成只有255和0组成时。 方法原理 利用255&#xff08;或者0&#xff09;和其他数字的&&#xf…

把十六进制字符转换成十进制数

2019独角兽企业重金招聘Python工程师标准>>> /*** Get the hex value of a character (base16).* param c A character between 0 and 9 or between A and F or* between a and f.* return An int between 0 and 15, or -1 if c was not a hex digit.*/public stat…

SQL Server更新某一列中多个字典码对应内容(sql示例)

目录示例-查询出多个字典码对应的内容示例-替换多个字典码对应的内容说明CHARINDEXFOR XML PATH示例-查询出多个字典码对应的内容 建立表格&#xff1a;学生-学习科目表student_study 注意&#xff1a;科目kemu列内容是字典码&#xff0c;需要更换成对应内容。 建立表格&…

mybatisPlus中的field-strategy(字段更新插入策略):null值插入和更新问题

目录mybatisPlus中null值插入和更新问题实际项目解决方法示例一实际项目解决方法示例二field-strategy字段更新插入策略介绍枚举类FieldStrategy源码枚举类字段简介mybatisPlus中null值插入和更新问题 配置mybatisPlus的项目中&#xff0c;默认进行了不是全量更新的策略&#…

linux构建主从域名服务器

实验步骤&#xff1a;一、构建主域名服务器1、安装域名服务&#xff08;BIND服务器软件包&#xff09;BIND软件包是目前Linux下使用最广泛的DNS服务器安装包&#xff0c;它可以运行到大多数UNIX服务器中&#xff0c;也包括Linux系统。RHEL4默认没有安装BIND服务器软件包&#x…

管道过滤器(Pipe-And-Filter)模式

按照《POSA(面向模式的软件架构)》里的说法&#xff0c;管道过滤器&#xff08;Pipe-And-Filter&#xff09;应该属于架构模式&#xff0c;因为它通常决定了一个系统的基本架构。管道过滤器和生产流水线类似&#xff0c;在生产流水线上&#xff0c;原材料在流水线上经一道一道的…

PCI_Express规范第七章解读-Software Initialization and configuration

7.Software Initialization and configuration PCI EXPRESS Configuration model 支持两种配置空间的访问机制&#xff1a; -PCI 兼容配置机制&#xff1a;100%的二进制兼容PCI 2.3中定义的&#xff0c;以及兼容早期的OS或类似的总线枚举和配置软件。 -PCI Express增强配置机制…