C语言局部搜索算法(爬山法,模拟退火法,遗传算法)求解八皇后问题

article/2025/11/10 11:44:21

C语言局部算法求解八皇后问题

  • 写在前面
  • 八皇后问题及局部搜索算法
  • 爬山法(hill-climbing searching)
    • 算法介绍
    • 代码实现
  • 退火法(simulated annealing)
    • 算法介绍
    • 代码实现
  • 遗传算法
    • 算法介绍
    • 代码实现

写在前面

该篇博客改自https://blog.csdn.net/chenxz_/article/details/83014641,习惯用python可以去参考他的代码。

八皇后问题及局部搜索算法

八皇后问题(英文:Eight queens),是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出的问题,是回溯算法的典型案例。
问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。计算机发明后,有多种计算机语言可以编程解决此问题。

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

爬山法(hill-climbing searching)

算法介绍

爬山法是指经过评价当前的问题状态后,限于条件去增加这一状态与目标状态的差异,经过迂回前进,最终达到解决问题的总目标。就如同爬山一样,为了到达山顶,有时不得不先上矮山顶,然后再下来,这样翻越一个个的小山头,直到最终达到山顶。可以说,爬山法是一种"以退为进"的方法,往往具有"退一步进两步"的作用,后退乃是为了更有效地前进。爬山法也叫逐个修改法、瞎子摸象法。

代码实现

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
#include<string.h>//初始化八皇后的布局
int inital(int *status) 
{int i,row;for(i=0;i<8;i++){row=rand()%8;status[i]=row;}return 0;
}//定义了两种方式展示八皇后布局
void display(int *status)
{int i;for(i=0;i<8;i++)printf("%d ",status[i]);printf("\n");/*for(i=0;i<8;i++){for(j=0;j<8;j++){if(status[i]!=j)printf("%d ",0);elseprintf("%d ",1);}printf("\n");}*/
}//得到八皇后有冲突的数目
int num_of_conflict(int *status)
{int num_of_conflict=0;int i,j;for(i=0;i<7;i++){for(j=i+1;j<8;j++){if((status[i]==status[j])||((j-i)==abs(status[i]-status[j])))num_of_conflict++;}}return num_of_conflict;
}//将一个八皇后布局拷贝给另一个
void copy(int *in, int *out)
{int i;for(i=0;i<8;i++)out[i]=in[i];
}//比较两个八皇后布局是否相同
int compare(int *status1,int *status2)
{int i;for(i=0;i<8;i++){if(status1[i]!=status2[i])return 0;}return 1;
}//改变布局,得到最小冲突的分布,即爬山的应用
int *get_min_conflict(int *status)
{int i,j,choose;int *min_status=(int*)malloc(sizeof(int)*9);memset(min_status,0,sizeof(int)*9);int new_status[8]={0};copy(status,min_status);for(i=0;i<8;i++){for(j=0;j<8;j++){copy(status,new_status);if(status[i]!=j){new_status[i]=j;if(num_of_conflict(new_status)<num_of_conflict(min_status))copy(new_status,min_status);else if(num_of_conflict(new_status)==num_of_conflict(min_status)&&num_of_conflict(new_status)!=num_of_conflict(status)){choose=rand()%2;if(choose==1)copy(new_status,min_status);}}}}return min_status;
}int main()
{int status[8]={0};int step=0,max_step=8;int *new_status=(int*)malloc(8*sizeof(int));memset(new_status,0,sizeof(int)*8);srand((unsigned)time(NULL));inital(status);printf("initual status:\n");display(status);printf("the num of conflict: %d\n\n",num_of_conflict(status));while(num_of_conflict(status)&&step<max_step){step++;new_status=get_min_conflict(status);;if(compare(new_status,status)){printf("the best answer:\n");display(status);printf("the num of conflict: %d\ncan not find an answer!\n",num_of_conflict(status));break;}copy(new_status,status);printf("the new status:\n");display(status);printf("the num of conflict: %d\n\n",num_of_conflict(status));if(num_of_conflict(status)==0)printf("find answer!\n");}getchar();return 0;
}

效果展示:
失败案例:
在这里插入图片描述
成功案例:在这里插入图片描述

退火法(simulated annealing)

算法介绍

模拟退火算法(Simulated Annealing,SA)最早的思想是由N. Metropolis [1] 等人于1953年提出。1983 年,S. Kirkpatrick 等成功地将退火思想引入到组合优化领域。它是基于Monte-Carlo迭代求解策略的一种随机寻优算法,其出发点是基于物理中固体物质的退火过程与一般组合优化问题之间的相似性。模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。模拟退火算法是一种通用的优化算法,理论上算法具有概率的全局优化性能,目前已在工程中得到了广泛应用,诸如VLSI、生产调度、控制工程、机器学习、神经网络、信号处理等领域。

代码实现

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
#include<string.h>int inital(int *status)
{int i,j;for(i=0;i<8;i++){j=rand()%8;status[i]=j;}return 0;
}void display(int *status)
{int i;for(i=0;i<8;i++)printf("%d ",status[i]);printf("\n");/*for(i=0;i<8;i++){for(j=0;j<8;j++){if(status[i]!=j)printf("%d ",0);elseprintf("%d ",1);}printf("\n");}*/
}int num_of_conflict(int *status)
{int num_of_conflict=0;int i,j;for(i=0;i<7;i++){for(j=i+1;j<8;j++){if((status[i]==status[j])||((j-i)==abs(status[i]-status[j])))num_of_conflict++;}}return num_of_conflict;
}void copy(int *in, int *out)
{int i;for(i=0;i<8;i++)out[i]=in[i];
}int compare(int *status1,int *status2)
{int i;for(i=0;i<8;i++){if(status1[i]!=status2[i])return 0;}return 1;
}//获取下一个布局,随机的
int *get_next_status(int *status, double T)
{	int i,j;int flag=0;int choice;int new_status[8]={0};int **next_status=(int**)malloc(sizeof(int*)*56);for(i=0;i<56;i++){next_status[i]=(int*)malloc(sizeof(int)*9);memset(next_status[i],0,sizeof(int)*9);}for(i=0;i<8;i++){for(j=0;j<8;j++){copy(status,new_status);if(status[i]!=j){new_status[i]=j;copy(new_status,next_status[flag++]);}			}}choice=rand()%56;if(num_of_conflict(next_status[choice])<=num_of_conflict(status)){return next_status[choice];}else{double E=num_of_conflict(status)-num_of_conflict(next_status[choice]);double probability=exp(E/T);double choose=(double)(rand()%999)/1000.0;if(choose<=probability){return next_status[choice];}}return status;		
}int main()
{double T=5.0;int*status=(int*)malloc(sizeof(int)*9);memset(status,0,sizeof(int)*9);int*new_status=(int*)malloc(sizeof(int)*9);memset(new_status,0,sizeof(int)*9);srand((unsigned)time(NULL));inital(status);printf("the initial status:\n");display(status);printf("the num of conflict: %d\n\n",num_of_conflict(status));while(num_of_conflict(status)){new_status=get_next_status(status,T);if(compare(new_status,status)) printf("it does not move\n");else{copy(new_status,status);printf("the new status:\n");display(status);printf("the num of conflict: %d\n\n",num_of_conflict(status));if(num_of_conflict(status)==0)printf("find  answer!\n");}T=T*0.99;if(T<0.0001){printf("max try, can not find an answer\n");break;}}getchar();return 0;
}

一般来说爬山法都能得到成功布局
代码效果:
在这里插入图片描述

遗传算法

算法介绍

遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。遗传算法已被人们广泛地应用于组合优化、机器学习、信号处理、自适应控制和人工生命等领域。

代码实现

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
#include<string.h>int inital(int *status)
{int i,j;for(i=0;i<8;i++){j=rand()%8;status[i]=j;}return 0;
}void display(int *status)
{int i;for(i=0;i<8;i++)printf("%d ",status[i]);printf("\n");/*for(i=0;i<8;i++){for(j=0;j<8;j++){if(status[i]!=j)printf("%d ",0);elseprintf("%d ",1);}printf("\n");}*/
}//展示种群所有布局
void display_all(int**all_status)
{int i;for(i=0;i<4;i++){display(all_status[i]);}
}//展示种群中各布局的冲突,调试的时候用的,代码运行不需要
void display_noConflict(int *noConflict)
{int i;for(i=0;i<4;i++){printf("%d ",noConflict[i]);}printf("\n");
}int num_of_conflict(int *status)
{int num_of_conflict=0;int i,j;for(i=0;i<7;i++){for(j=i+1;j<8;j++){if((status[i]==status[j])||((j-i)==abs(status[i]-status[j])))num_of_conflict++;}}return num_of_conflict;
}//得到种群中最小的冲突数
int get_minConflict(int **all_status)
{int min=999;int i;for(i=0;i<4;i++){if(num_of_conflict(all_status[i])<min)min=num_of_conflict(all_status[i]);}return min;
}int num_of_noConflict(int*status)//我也不知道为什么要定义这个函数,有num_of_conlict好像就够了 
{return 28-num_of_conflict(status);
}void copy(int *in, int *out)
{int i;for(i=0;i<8;i++)out[i]=in[i];
}int compare(int *status1,int *status2)
{int i;for(i=0;i<8;i++){if(status1[i]!=status2[i])return 0;}return 1;
}//获得种群中所有个体冲突数集合
int get_sum(int*num)
{int i;int sum=0;for(i=0;i<4;i++)sum+=num[i];return sum;
}//随机返回种群中四个个体中的一个
int *get_parent(int**all_status,int*noConflict) //我也不知道为什么要这么写,完全可以直接调用rand()返回0到3的随机数,可能是为了看起来更像遗传吧 
{int choice=rand()%get_sum(noConflict);if(choice<noConflict[0])return all_status[0];else if(choice>=noConflict[0]&&choice<(noConflict[0]+noConflict[1]))return all_status[1];else if(choice>=(noConflict[0]+noConflict[1])&&choice<(noConflict[0]+noConflict[1]+noConflict[2]))return all_status[2];return all_status[3];
}//种群中个体随机变异
int **variation(int **all_status)
{int i,col,row;for(i=0;i<4;i++){row=rand()%8;col=rand()%8;all_status[i][row]=col;}return all_status;
}//种群中个体遗传
int **inheritance(int **all_status)
{int flag=0;int i,j,num;int *father,*mother;int child1[8]={0};int child2[8]={0};int *noConflict=(int*)malloc(sizeof(int)*5);memset(noConflict,0,sizeof(int)*5);int **new_all_status=(int**)malloc(sizeof(int*)*4);for(i=0;i<4;i++){new_all_status[i]=(int*)malloc(sizeof(int)*9);memset(new_all_status[i],0,sizeof(int)*5);noConflict[i]=num_of_noConflict(all_status[i]);}for(i=0;i<2;i++){father=get_parent(all_status,noConflict);mother=get_parent(all_status,noConflict);while(compare(father,mother))mother=get_parent(all_status,noConflict);copy(father,child1);copy(mother,child2);num=rand()%7;for(j=0;j<num+1;j++){child1[j]=child2[j];child2[j]=father[j];}copy(child1,new_all_status[flag++]);copy(child2,new_all_status[flag++]);}return new_all_status;
}//种群中是否有成功布局
int find_answer(int**all_status)
{int i;for(i=0;i<4;i++){if(num_of_noConflict(all_status[i])==28){printf("find answer!\n");display(all_status[i]);return 1;}}return 0;
}int main()
{int i;srand((unsigned)time(NULL));int **all_status=(int**)malloc(sizeof(int*)*4);for(i=0;i<4;i++){all_status[i]=(int*)malloc(sizeof(int)*9);memset(all_status[i],0,9);inital(all_status[i]);}printf("the inital all_status:\n");display_all(all_status);printf("the min all_status: %d\n\n",get_minConflict(all_status));all_status=inheritance(all_status);int vari_prob;while(!find_answer(all_status)){vari_prob=rand()%11;if(vari_prob==1){all_status=variation(all_status);printf("have a variation, and the all_status:\n");display_all(all_status);printf("the min conflict: %d\n\n",get_minConflict(all_status));}else{all_status=inheritance(all_status);printf("the next all_status:\n");display_all(all_status);printf("the min conflict: %d\n\n",get_minConflict(all_status));}}	
}

代码效果展示(目前还在演化):
在这里插入图片描述


http://chatgpt.dhexx.cn/article/Xh346Qka.shtml

相关文章

八皇后问题和八数码问题的最陡上升爬山法、首选爬山法、随机重启爬山法、模拟退火算法的分析和实现

源起 人工智能的第二次作业课后的某题要求对八皇后问题和八数码问题分别用最陡上升爬山法、首选爬山法、随机重启爬山法、模拟退火算法来实现,并且分析他们的性能。 分析 我们发现要求实现的各个算法是有共同点的,比如,八皇后问题相关算法拥有相同的状态空间,每个算法都有…

【人工智能】首选爬山法+随机交换法实现N皇后问题求解(C语言)

1.原理 爬山法&#xff08;Hill Climbing&#xff09;是一种局部搜索算法。局部搜索算法不关心求解目标的路径&#xff0c;只要求找到符合要求的解&#xff0c;通常对最优化问题十分有用。爬山法使用启发式函数&#xff08;或代价评估函数&#xff09;确定“标高”&#xff0c…

【学习笔记】我命由天不由我之随机化庇佑 —— 爬山法 和 模拟退火法

以下均假设最优解是在最低点。 爬山法 爬山算法是一种局部择优的方法&#xff0c;采用启发式方法&#xff0c;是对深度优先搜索的一种改进&#xff0c;它利用反馈信息帮助生成解的决策。 直白地讲&#xff0c;就是当目前无法直接到达最优解&#xff0c;但是可以判断两个解哪…

人工智能-爬山法解决八数码问题-python源码

问题描述&#xff1a; 在一个3*3的方棋盘上放置着1,2,3,4,5,6,7,8八个数码,每个数码占一格,且有一个空格。这些数码可以在棋盘上移动&#xff0c;其移动规则是&#xff1a;与空格相邻的数码方格可以移入空格。现在的问题是&#xff1a;对于指定的初始棋局和目标棋局&#xff0c…

人工智能-爬山法解决八皇后问题-python源码

问题简述&#xff1a; 八皇后问题&#xff0c;一个古老而著名的问题&#xff0c;是回溯算法的典型案例。该问题由国际西洋棋棋手马克斯贝瑟尔于 1848 年提出&#xff1a;在 88 格的国际象棋上摆放八个皇后&#xff0c;使其不能互相攻击&#xff0c;即任意两个皇后都不能处于同一…

树的搜索问题1(深度优先、广度优先,爬山法和best-first)

前言 我们在解决问题中经常使用到的数据结构一定少不了树&#xff0c;在数据结构这一大块中&#xff0c;我们对每一个结构都会讲各种形形色色的操作&#xff0c;比如栈的压栈出栈&#xff0c;树的各种遍历&#xff0c;但其实数据结构最重要的操作其实是搜索。如果我们不知道链…

TSP问题解决:模拟退火、贪心法、爬山法,Python实现

TSP问题解决&#xff1a;模拟退火、贪心法、爬山法&#xff0c;Python实现这里写目录标题 一、TSP问题二、简单介绍&#xff1a;贪心法、爬山法、模拟退火三、python代码实现四、分别用这三种方法得出结果&#xff0c;进行比较 一、TSP问题 1、TSP问题描述 简单来说&#xff0…

爬山法实现 八皇后问题 (Python 实现)

本文主要简单阐述爬山法的基本算法思想&#xff0c;并给出用此算法实现八皇后问题详细过程 最基本的爬上搜索算法表示&#xff1a;(节选自《人工智能》第二版)&#xff1a; function HILL-CLIMBING(problem) return a state thate is a locak maximum inputs: problem …

爬山法求解八皇后问题的全部解法

爬山法求解八皇后问题的全部解法 程序的概要设计思想初始状态冲突函数寻找邻居状态寻找全部解集 程序主要函数的作用运行结果截图Python源代码 程序的概要设计思想 爬山算法是一种局部贪婪算法&#xff0c;每次更新一次状态&#xff0c;都对相邻状态的冲突状态进行排序&#x…

Python启发式算法中爬山法的讲解及解方程问题实战(超详细 附源码)

一、启发式算法 还有一类重要的迭代法&#xff0c;它的迭代关系式不依赖问题的数学性能&#xff0c;而是受某种自然现象的启发而得到&#xff0c;称为启发式算法&#xff08;Heuristic Algorithm&#xff09;&#xff0c;如爬山法、遗传算法、模拟退火算法、蚁群算法等。 启发…

人工智能:爬山法、随机重启爬山法、模拟退火算法、遗传算法、启发式搜索方法解决八数码和八皇后问题

摘要 本文主要分为两个部分&#xff0c;分别采用实验对比对不同的方法进行分析。第一&#xff0c;以八数码问题和八皇后问题为例&#xff0c;对比爬山法&#xff0c;随机重启爬山法&#xff0c;模拟退火算法&#xff0c;遗传算法的搜索性能。第二&#xff0c;以八数码问题为例…

进化优化算法--第二章:爬山法

算法2.1&#xff1a; 最快上升爬山法 x0 <- 随机生成的个体 while not ( 终止准则)计算x0的适应度f(x0)For 每一个解的特征 q1,2,,...nxq <- x0 用一个随机变异替换xq的第q个特征计算xq的适应度f(xq)获取下一个更优的解:寻找使f(xq)最大的xq, 令其等于x, x <- argma…

Python:爬山法/随机重启爬山法/允许侧移的爬山法解决八皇后问题

文章目录 1 八皇后问题2 程序代码2.1 程序12.2 程序22.3 程序32.3.1 爬山法2.3.2 随机重启爬山法2.3.3 允许皇后侧移的爬山法 3 评价 1 八皇后问题 有一个8乘8的棋盘&#xff0c;现在要将八个皇后放到棋盘上&#xff0c;满足&#xff1a;对于每一个皇后&#xff0c;在自己所在…

爬山法和模拟退火

文章目录 前言一、爬山法1.算法步骤2.算法局限性 二、模拟退火1.算法步骤2.注意点3.例题求费马点保龄球均分数据 总结 前言 爬山法和模拟退火都为随机化算法&#xff0c;考场想不到正解时可用来骗分&#xff0c;通常效果较好。模拟退火是基于爬山法的优化。 一、爬山法 爬山法是…

搜索算法——爬山法

不断更新中...... 一、 爬山算法&#xff1a;爬山算法是一种简单的贪心搜索算法&#xff0c;该算法每次从当前位置的临近空间中选择一个最优解作为当前解&#xff0c;直到达到一个局部最优解。爬山算法可以类比成一个有失忆的人在浓雾中爬山。这里就揭示了爬山算法的两个问题…

搜索 —— 启发式搜索 —— 爬山法

【概述】 爬山法&#xff08;Hill Climbing&#xff0c;HC&#xff09;是一种局部择优的贪心搜索算法&#xff0c;其本质上是梯度下降法。 该算法每次从当前的节点开始&#xff0c;与周围的邻接点进行比较&#xff1a; 若当前节点是最大的&#xff0c;那么返回当前节点&…

Linux:快速查看IP地址及修改IP地址

导读Linux下如何快速查看IP地址及修改IP地址&#xff0c;有一个方法供参考 查ip 方法/步骤1: 打开linux操作系统在进入到界面 方法/步骤2: 在桌面右击打开终端。 方法/步骤3: 终端里输入ifconfig -a命令在回车键 方法/步骤4: 如下图可以看到了ip地址。 修改ip 方法/…

Linux Ubuntu查看IP信息的两种方式Ubuntu中检查你的 IP 地址

论使用什么系统&#xff0c;都有用到ip地址的时候&#xff0c;习惯了windows系统的人很容易就能查找出系统的ip&#xff0c;但是在linux系统如何查看ip呢&#xff1f;作为Linux新手&#xff0c;以Ubuntu的使用经验&#xff0c;我知道Ubuntu查看IP有两种方式。 第一种是在终端中…

Linux查询出口IP

查询的方式是通过Linux的curl访问查询ip的网站进行查询 具体步骤&#xff1a; 1.查询查询ip网站的ip 2.配置Linux的hosts文件 在/etc中的hosts文件增加上面的域名和ip&#xff08;注意&#xff1a;是ifconfig&#xff0c;不是ipconfig&#xff09; 3.在ssh命令下执行 curl ifc…

Linux 查看本地ip

Linux 查看本地ip 终端中输入指令ifconfig -a终端中输入指令hostname -I通过图形界面查看IP地址&#xff08;还未试通&#xff09; 终端中输入指令ifconfig -a 弹出的IP地址有点多 。 终端中输入指令hostname -I 会直接显示本机在局域网内的IP地址&#xff0c;但可能会显示多…