设置初始温度和初始解
对这个解进行各种各样的扰动
如果扰动得到更优解,则取他
否则利用函数exp(-d_Len/T),求概率进而判断这个解是否取
随着温度的降低,解的改变可能性就越小
看代码吧,有空再补充一下
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<ctime>
#include<iostream>
#include<cmath>
using namespace std;
const int oo=100000000;
const double T0=6000.0; // 初始温度
const double T_end=0.0001; // 结束温度
double T;
const double q=0.99;
const int L=2000;
int tmp[100],ans[100];
int g[100][100];
time_t start,finish;
int cnt,n,m,x,y,w;
int path[100],path_2[100];
void Init() {
cnt=0;
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) if (i==j) g[i][j]=0; else g[i][j]=oo;
for (int i=1; i<=m; i++) {
scanf("%d%d%d",&x,&y,&w);
if (w<g[x][y]) g[x][y]=g[y][x]=w;
}
start=clock(); //算法开始的时间
for (int i=1; i<=n; i++) path[i]=i;
}
void Disturb1() {
int x=rand();
int y=rand();
int pos1=x%n+1;
int pos2=y%n+1;
swap(path_2[pos1],path_2[pos2]);
}
void Disturb2() {
int x=rand()%n+1;
int y=rand()%n+1;
int tmp[100];
int cnt=0;
if (x>y) swap(x,y);
// [1..x][x+1..y][y+1..n]----> [y+1..n][x..y][1..x-1]
for (int i=y+1; i<=n; i++) tmp[++cnt]=path_2[i];
for (int i=x; i<=y; i++) tmp[++cnt]=path_2[i];
for (int i=1; i<=x-1; i++) tmp[++cnt]=path_2[i];
for (int i=1; i<=n; i++) path_2[i]=tmp[i];
}
void Disturb3() {
int x=rand()%n+1;
int y=rand()%n+1;
int tmp[100];
int cnt=0;
if (x>y) swap(x,y);
// [1..x][x+1..y][y+1..n]----> [y+1..n][y..x][1..x-1]
for (int i=y+1; i<=n; i++) tmp[++cnt]=path_2[i];
for (int i=y; i>=x; i--) tmp[++cnt]=path_2[i];
for (int i=1; i<=x-1; i++) tmp[++cnt]=path_2[i];
for (int i=1; i<=n; i++) path_2[i]=tmp[i];
}
void SA() {
T=T0;
while (T>T_end) {
for (int i=1; i<=L; i++) { // 每个温度的迭代次数
for (int j=1; j<=n; j++) path_2[j]=path[j]; // 初始化解
int t=rand() % 900;
if (t<=300) Disturb1(); else if (t<=600) Disturb2(); else Disturb3(); // 对这个解进行扰动
int len1=0,len2=0;
for (int j=2; j<=n; j++) {
len1+=g[path[j]][path[j-1]];
len2+=g[path_2[j]][path_2[j-1]];
}
len1+=g[path[n]][path[1]];
len2+=g[path_2[n]][path_2[1]];
int d_Len=len2-len1;
// 以下是Metropolis准则
if (d_Len>=0) {
double r=((double)rand())/(RAND_MAX); // 在0-1之间的值
if (exp(-d_Len/T)>=r) { // 按概率取
for (int j=1; j<=n; j++) path[j]=path_2[j];
}
} else { // 比原来的解更优秀-*/
if (d_Len<=0) for (int j=1; j<=n; j++) path[j]=path_2[j];
}
}
cnt++;
T*=q;
}
}
void Outit() {
int ans=0;
finish=clock(); // 退火过程结束
double duration=((double)(finish-start))/CLOCKS_PER_SEC; // 计算时间
cout<<"找到的最优解为"<<endl;
for (int i=1; i<=n; i++) cout<<path[i]<<" -> "; cout<<path[1]<<endl;
ans=0;
for (int i=2; i<=n; i++) ans+=g[path[i]][path[i-1]]; ans+=g[path[n]][path[1]];
cout<<"路线总长度为 "<<ans<<endl;
cout<<"--------------------------------"<<endl;
cout<<"模拟退火算法"<<endl;
cout<<"初始温度: "<<T0<<"; 降温系数: "<<q;
cout<<"; 每个温度的迭代次数: "<<L<<endl;
cout<<"一共降温 "<<cnt<<" 次"<<endl;
printf("程序运行耗时:%lf秒.\n",duration);
}
int main() {
freopen("data.txt","r",stdin);
srand(time(NULL));
Init();
SA();
Outit();
}