【人工智能】模拟退火算法解决N皇后问题(C语言)

1.原理

模拟退火算法(Simulated Annealing Algorithm )其实也是一种随机爬山法(Hill Climbing)。其不同之处在于模拟退火算法在下一个状态情况“变坏”的情况下以指数级概率接受该移动,这种随机接受方法可以使得爬山法跳出局部山峰的平坦区域,从而得到全局最优解

算法开始时,设置初始温度T(应该是要足够大才行)、温度下降速率rate(应该是设置足够小),然后开始迭代:

(0)计算curr(curr为当前改变状态后的评估值),如果curr=0,则算法结束,找到全局最优解,否则进行下面(1)-(4)反复迭代。

(1)设dE=curr-last(curr为当前改变状态后的评估值,last为上一次评估值)。

(2)如果dE<=0,则接受该状态改变

(3)如果dE>0,则以概率p接受该状态改变,其中概率p的计算公式为:

                                           p=e^{dE/T}

上面公式可以求得全局最小值,如果指数部分加一个负号,可以求得全局最大值。(也许吧??)

分析:一开始T很大,p接近1或超过1,很大概率是接受该后继状态;接下来,T逐渐下降,变得越来越小,由于dE<0,故p会很小,这时就很少能接受该后继状态了。

(4)每一轮次结束后修改温度T=T*rate,如果T小于设定的最小温度,算法结束,没有找到解。

2.代码实现

其数据结构和计算评估值函数参见上一篇文章:https://blog.csdn.net/obestboy/article/details/86695712

int simulatedAnnealing(int s[])
{
       int h=heuristic(s);//评估函数见前一博文
       if(h==0) return 0;
       int curr=h;//改变状态后的评估值
       int last=h;//上一次评估值
       int c=0;//迭代轮次计数器
       double T=SIZE*SIZE*1000;//初始温度
       double rate=0.999; //温度下降速率
       double minT=0.00001;
       int k1=0,k2=0;//两个计数器而已
       while (1)
       {
       	   int counter=0;
       	   c++;
           for(int i=0;i<SIZE;i++) //第i行 
           {
              for(int j=0;j<SIZE;j++)//第i行皇后放第j列上 
              {
                 if(j!=s[i]) //s[i]为第i行皇后的现在列号 
                 {
                   //临时调整:将第i行的皇后放在第j列上,计算评估值 
                    curr=adjust(s,i,j,last);
                    counter++;
                    if(curr==0)
                    {	
                        printf("\n迭代次数:%d\n",c);
                        printf("\n执行次数=%d,未执行次数=%d\n",k1,k2);
                        accept(s,i,j);
                        return c;
                    }
                    int dE=curr-last;
                    int p=(int) 1000*exp(1.0*dE/T);//计算概率
                    //下面myRandom函数见前一博文
                    int ss=myRandom(0,1000,counter);
                    if(dE<=0 )
                    {
                       accept(s,i,j);
                       last=curr;
                       break;
                     }
                    //执行概率大于生成的概率:执行
                    else if(p>=ss) //可以和上面的合并,主要看有多少没执行或执行
                    {
                       accept(s,i,j);
                       last=curr;
                       k1++;
                       break;						
                     }
                    else k2++;//printf("没执行\n");
                 }
             }  
           }
           T*=rate;//温度下降
           if(T<minT)
           {
                printf("没有找到!\n");
                printf("\n迭代次数:%d\n",c);
                printf("\n执行次数=%d,未执行次数=%d\n",k1,k2); 
                return c;
           }
     }
}

3.结果分析

模拟退火算法速度慢于爬山法,其初始温度、温度下降速率等的设置比较费劲,需要反复测试,代码中的设置对于某些个数的皇后不一定能找到最优解。(500以下应该能找到解)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值