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,一经查实,立即删除!

相关文章

用JavaScript嵌入你的SWF

用JavaScript嵌入你的SWFswfobject.embedSWF(swfUrl, id, width, height, version, expressInstallSwfurl, flashvars, params, attributes)有5个必须的参数和4个可选的参数&#xff1a;swfUrl&#xff08;String&#xff0c;必须的&#xff09;指定SWF的URL。 id&#xff08;S…

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

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

Ghost安装之后,键盘出现字符出现乱码

今天我安装了G版本的WinServer2003,安装完成之后键盘打字出现乱字符,后来终于发现原来我的输入法模式为数字模式,按FN&#xff0b;insert可以切换回来,问题就解决了.转载于:https://blog.51cto.com/yaojian/314847

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

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

关于三极管偏置电路的思考

最近在做十年前应该做的事情&#xff0c;从最基本的模拟电路实验开始&#xff0c;了解电子的基本概念。还好&#xff0c;对事物的理解&#xff0c;随着阅历增加&#xff0c;理解的程度也不一样。从三极管偏置电路&#xff0c;我想到了人的自我修养和调整。当电路调整到一个合适…

搜索引擎指令站长常用搜索引擎命令汇总

身为一个网站管理员用好各大搜索引擎一些特殊指令&#xff0c;是最基本的网站SEO。逅客百度Google取经看到有前人整理的几个搜索引擎常用指令&#xff0c;单独使用是最基本&#xff0c;能综合使用就会体验搜索的另类魅力。以下搜索引擎指令都以学海网(www.xuehai.net)为例。 一…

Socket源码相关——SocketAddress和InetSocketAddress

目录我的学习过程我的心路历程思考总结我的学习过程 昨天学习qiujuer老师的《Socket网络编程进阶与实战》实战课程中&#xff0c;写了一个简易的client-server聊天项目。我的学习方法是根据课程的一部分思路提示后&#xff0c;自己独自进行编写&#xff0c;出现了很多问题&…

三轮哥

灰太狼发现自从有了犀利哥开始&#xff0c;什么什么哥越来越流行了&#xff0c;就跟当初的各种“门”一样&#xff0c;这不&#xff0c;网上盛传许久的三轮哥&#xff0c;灰太狼今天才有幸看到。 不过话说回来&#xff0c;类似三轮哥这样的人物还是少出一点的好&#xff0c;这玩…

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

目录我的心路历程我的学习概括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;通…

gradle下bug修正后问题仍存在解决思路

目录我的学习过程我的学习心路热加载配置bug问题总结我的学习过程 前天写的client-server聊天项目写完后&#xff0c;今天进行了调试。我用到的是out目录下的server.class文件和client.class文件。 先后启动两个命令行窗口来进行测试的。 使用java server启动服务端窗口。 再使…

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环境配…

数字示波器的激烈竞争

计算机、通信以及消费类电子产业的快速发展成为示波器发展的不竭动力&#xff1b;厂商不断从技术上对示波器进行改进更使其发展日新月异。 <?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />数字示波器自它诞生的第一天起&#xf…

git pull和push整理和归纳

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

重装vcenter后恢复原来制作的模板!

重新安装vcenter后发现原来用vcenter创建的模板没有了。清单中只显示现有的4台虚拟机&#xff0c;没有显示模板。其实找回来也很简单&#xff01;在清单中找到数据存储&#xff0c;在相应的模板文件夹中找到的.vmtx文件添加到清单中去即可&#xff01;转载于:https://blog.51ct…

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

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

如何调整HOOK的跳转指令

可以按这样的方式来存放 长度A 长度A 用于调整Short JMP 用于存放一些信息 |调整后的原HOOK代码 |原始代码(HOOK) |临时LONG JMP区| 信息区| 1). 调整…

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

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