#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int s,way[1001],ans[1001];
double tem,mop,l[1001][1001];
bool flag[1001];
bool judge(double l)//概率选择
{
double op=rand()/(double)RAND_MAX;
return exp(l)>op;
}
int main()
{
scanf("%d",&s);
for(int i=1;i<=s;++i)
for(int j=1;j<=s;++j)scanf("%lf",&l[i][j]);//读入距离
srand(time(NULL));
flag[1]=1;
way[1]=1;
for(int i=2;i<=s;++i)
{
int k=rand()%(s-1)+2;
while(flag[k])k=rand()%(s-1)+2;
flag[k]=1;
way[i]=k;
tem+=l[way[i-1]][way[i]];
}//生成初始解
tem+=l[1][way[s]];
way[s+1]=1;
mop=tem;
way[s+1]=1;
double fir=1000/*初始温度*/,op=0.98/*冷却速度*/;
for(int i=1;i<=s+1;++i)ans[i]=way[i];
while(fir>=1e-4)
{
int o=rand()%(s-1)+2,p=rand()%(s-1)+2;//
while(p==o)p=rand()%(s-1)+2;//随机寻找下一步
double add=0;
swap(way[o],way[p]);
for(int i=1;i<=s;++i)add+=l[way[i]][way[i+1]];
add-=tem;
swap(way[o],way[p]);
if(add<0)//如果更优,直接转移
{
swap(way[o],way[p]);
if(mop>tem+add)
{
mop=(tem+=add);
for(int i=1;i<=s+1;++i)ans[i]=way[i];
}
}
else
if(judge(add/fir))//否则根据Metropolis抽样稳定准则概率转移
{
tem+=add;
swap(way[o],way[p]);
}
fir*=op;
}
for(int i=1;i<=s;++i)printf("%d->",way[i]);
printf("%d\n%lf\n",way[s+1],mop);
return 0;
}
/*
5
0 3 3 2 6
3 0 7 3 2
3 7 0 2 5
2 3 2 0 3
6 2 5 3 0
*/
知识链接:
Metropolis抽样稳定准则:若Δt′<0则接受S′作为新的当前解S,否则以概率exp(-Δt′/T)接受S′作为新的当前解S。