模拟退火(SA)搜索算法

所谓的爬山算法实际上就是简单的贪心算法,贪心算法通过从当前解的临近空间选择一个最优的解作为新的当前解,因此这个解很有可能是局部最优解,而不是全局最优的。因为A的领域周围没有比他更优的解了。

 

模拟退火搜索通过允许向不好的状态移动来避开局部最值点,但频率逐渐降低。它是一种基于蒙特卡洛思想设计的近似求解最优化问题的方法。

伪代码如下:

  choose an initial solution X0  randomly                      //随机的选择一个初始解X0
  give an initial temperature T0 , X ← X0, T ← T0       //初始化温度T0
  while the stop criterion is not yet satisfied do            //停止准则不满足则
   {   for i ← 1 to  L do                                                  //Markov 链的长度 L
        {  pick a solution  X'∈N(X) randomly                  //随机选择临域内一个解X',为逃离局部最值点
           Δf ← f(X')-f(X)                                                   //后续节点-当前节点
           if Δf<0  then  X ← X'                                         
           else  X ← X' with  probability exp(- Δf/T)  }        //  以exp(- Δf/T)的接受概率接受X'
   T← g(T)    //generally, T ← aT    }                             //温度下降
  return X
 

void SimulatedAnnealing()

{

  蒙特卡洛随机产生一个初始解X0;

     初始化温度T、迭代次数L、降温系数TA、迭代误差E

      for(int i=0;i<L;i++)//退火过程

     {

     计算与新解所对应的目标函数差df;

     if(df<0)

        接受当前的解X′作为新解X;

     else

       以概率exp(-Δt′/T)接受X′作为新的当前解X;

     T = AT * T ; //降温退火

     }

}

模æéç«ç®æ³çåçãä¼ç¼ºç¹ãæµç¨ãåºç¨å®ä¾
 

#include<iostream>
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<time.h>
#include<stdlib.h>
#include<stdio.h> 
//#include <windows.h>

#define MAX 10000
#define INF 10000000 
#define E 0.000000001  // 迭代误差 
#define L 40000    // 迭代次数 
#define AT 0.999   // 降温系数 
#define T 1       // 初始温度 

#define N 5//城市个数
using namespace std; 

struct element{     //用来排序的数据结构 
	int data;  // 数据 
	int index;  // 序号 
};


int tsp(int d[][N], int n, double e,int l,double at,double t,int s0[]);  //利用模拟退火算法求解最短路径 
int cmp(const void *a,const void *b); //升序排列 
void rand_of_n(int a[],int n);  //产生 1-n 的随机排列并存到 a[] 中
int random(int m,int n);
//int dis[MAX][MAX];   // d[i][j] 表示客户i到客户j的距离,0 表示起始点 


int dis[N][N]={0,1,57,20,81, 
        1,0,59,49,36, 
              57,59,0,90,82, 
              20,49,90,0,75, 
              81,36,82,75,0 };
              
void rand_of_n(int a[],int n){
	int i;
	struct element ele[MAX];
	srand((int)time(0));  // 初始化随机数种子 
	for(i=0;i<n;i++){
		ele[i].data=rand();  // 随机生成一个数 
		ele[i].index=i+1;
	}
	qsort(ele,n,sizeof(ele[0]),cmp);  //排序 
	for(i=0;i<n;i++){
		a[i]=ele[i].index;
	}
}

int random(int m,int n){   //产生m-n的随机数
	int a;
	double x=(double)rand()/RAND_MAX;
	a=(int)(x*(n-m)+0.5)+m;
	return a;
}	

int cmp(const void *a,const void *b){   // 升序排序
	return((struct element*)a)->data - ((struct element*)b)->data;
}


int tsp(int d[][N], int n, double e,int l,double at,double t,int s0[]){
	int i,j,s[N],sum,temp;
	sum=INF; 
	for(i=0;i<1000;i++){  //利用蒙特卡洛方法产生初始解
		rand_of_n(&s[1],n);
		s[0]=0; s[n+1]=0;  //第一个和最后一个点为起始点 
		temp=0;
		for(j=0;j<=n;j++)
			temp=temp+d[s[j]][s[j+1]];
		if(temp<sum){
			for(j=0;j<=n+1;j++)
				s0[j]=s[j];
			sum=temp;
		} 
	}
	
	for(i=0;i<l;i++){    //退火过程 
		int c1,c2;
		c1=random(1,n);
		c2=random(1,n);
		if(c1>c2){
			int temp=c2; c2=c1; c1=temp;
		} 
		if(c1==c2)
			continue;
		int df=d[s0[c1-1]][s0[c2]] + d[s0[c1]][s0[c2+1]] - d[s0[c1-1]][s0[c1]] - d[s0[c2]][s0[c2+1]]; //计算代价函数
		if(df<0){  //接受准则
			while(c1<c2){ 
				int temp=s0[c2]; s0[c2]=s0[c1]; s0[c1]=temp;
				c1++;
				c2--;
			}
			
			sum=sum+df;
		} 
		else if(exp(-df/t)>((double)rand()/RAND_MAX)){
			while(c1<c2){
				int temp=s0[c2]; s0[c2]=s0[c1]; s0[c1]=temp;
				c1++;
				c2--;
			}

			sum=sum+df;
		}
		t=t*at;//线性降温
		if(t<e)
			break;
	}
	return sum;
}



int main(){
    //DWORD start, stop;
    int i,j;

	int sum,sum0,s0[MAX]; 
	sum0=0;   //顺序遍历时的路程 
	for(i=0;i<N;i++)
		{sum0=sum0+dis[i][i+1];}
	sum0=sum0+dis[N][0];
	sum=tsp(dis,N, E,L,AT,T,s0);
	
	for(i=1;i<=N;i++)
		cout<<s0[i]<<" ";


	cout<<endl; 	

	
	printf("模拟节点个数 %d\n", N);

	return 0; 
}

缺点:收敛速度慢、不能保证得到全局最优值。

增加获得全局最优值的可能性:

  1. 增加模拟运行的时间(迭代次数);
  2. 多次重新启动,重置所有变量并开始新的SA,从不同搜索区域的位置开始。

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Travis.X

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值