C++版本
遗传算法、模拟退火、蚁群算法、Hopfield神经网络、禁忌搜索,部分思路参考网络或者Paper。
//遗传算法解决TSP问题,35s
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int times = 3000;//遗传代数
const int chrom = 34; //染色体长度
const int num = 380; //染色体数量
int pc = 80, pm = 6;
int tmp[num+3];
double mp[chrom+3][chrom+3]={0}; //图
int vis[chrom+3], cur;
double fitness[num+3], INF = 1e13;
vector<int>g[num+3], neb[chrom+3], nb[chrom+3];
vector<int>debug[times+3];
double debug2[times+3];
struct node{
double x, y;
}point[chrom+3];
double dis(int u, int v){
double x = point[u].x-point[v].x;
double y = point[u].y-point[v].y;
return sqrt(x*x+y*y);
}
void init_map(){//初始化边的情况
for(int i=0; i<chrom; ++i){
scanf("%lf%lf",&point[i].x,&point[i].y);
}
for(int i=0; i<chrom; ++i){
for(int j=0; j<chrom; ++j){
mp[i][j] = dis(i,j);
}
}
}
void encoding(){//对染色体编码
vector<int>id;
for(int i=0; i<chrom; ++i) id.push_back(i);
for(int i=0; i<num; ++i){
random_shuffle(id.begin(), id.end());
g[i] = id;
}
}
double cal_distance(vector<int>x){//计算染色体的距离
double res = mp[x[0]][x[chrom-1]];
for(int i=0; i<chrom-1; ++i)
res += mp[x[i]][x[i+1]];
return res;
}
void get_fitness(){//计算染色体的适应度
for(int i=0; i<num; ++i){
fitness[i] = INF/cal_distance(g[i]);
}
}
bool cmp(int x, int y){
return fitness[x] > fitness[y];
}
void selection(){//选自算子
for(int i=0; i<num; ++i) tmp[i] = i;
sort(tmp, tmp+num, cmp);//按适应度排序
int L = (int)(num*0.3);
for(int i=L*9/10; i; --i){
int x = rand()%L+L;
int y = rand()%L;
g[tmp[x]] = g[tmp[y]];
}
}
vector<int> core(int flag, vector<int>neb[]){
memset(vis, 0, sizeof(vis));
for(int i=0; i<chrom; ++i) nb[i] = neb[i];
vector<int>ans;
vector<pair<double,int> >best;
ans.push_back(g[flag][0]);
for(int i=0; i<chrom-1; ++i){
int x = ans[i];
best.clear();
vis[x] = 1;
for(int j=0; j<nb[x].size(); ++j){
int y = nb[x][j];
best.push_back({mp[x][y], y});
auto it = find(nb[y].begin(), nb[y].end(), x);
if(it != nb[y].end()){
nb[y].erase(it);
}
}
if(!best.empty()){
sort(best.begin(), best.end());
ans.push_back(best[0].second);
}
else{
double min_dis = 1e9;
int min_id = 0;
for(int j=0; j<chrom; ++j){
if(!vis[j] && mp[x][j] < min_dis){
min_dis = mp[x][j];
min_id = j;
}
}
ans.push_back(min_id);
}
}
return ans;
}
pair<double, int> get_best(){
double min_dis = 1e9;
int min_id = 0;
for(int i=0; i<num; ++i){
double x = cal_distance(g[i]);
if(min_dis > x){
min_dis = x;
min_id = i;
}
}
return {min_dis,min_id};
}
void crosscover(){
for(int i=0; i<num/2; ++i){
if((rand()%100+1) <= pc){
for(int j=0; j<chrom; ++j) neb[j].clear();
for(int j=0; j<chrom; ++j){
neb[g[i][j]].push_back(g[i][(j+1)%chrom]);
neb[g[i][j]].push_back(g[i][(j-1+chrom)%chrom]);
neb[g[num-i-1][j]].push_back(g[num-i-1][(j+1)%chrom]);
neb[g[num-i-1][j]].push_back(g[num-i-1][(j-1+chrom)%chrom]);
}
for(int j=0; j<chrom; ++j){
sort(neb[j].begin(), neb[j].end());
neb[j].erase(unique(neb[j].begin(), neb[j].end()), neb[j].end());
}
vector<int>tmp1 = core(i, neb);
vector<int>tmp2 = core(num-i-1, neb);
vector<pair<double,vector<int> > >best;
best.push_back({cal_distance(g[i]), g[i]});
best.push_back({cal_distance(g[num-i-1]), g[num-i-1]});
best.push_back({cal_distance(tmp1), tmp1});
best.push_back({cal_distance(tmp2), tmp2});
sort(best.begin(), best.end());
g[i] = best[0].second;
g[num-i-1] = best[1].second;
}
}
}
void mutation(){
int gai = pm;
if(cur >= times*3/4) gai = pm*5;
for(int i=0; i<num; ++i){
if((rand()%100+1) <= gai){
int x = rand()%chrom, y = rand()%chrom;
if(x > y) swap(x, y);
for(int j=0; x+j<=(x+y>>1); ++j){
swap(g[i][x+j], g[i][y-j]);
}
}
}
}
int main(){
//freopen("a.txt", "r", stdin);
//freopen("2.txt", "w", stdout);
srand(time(0));
init_map();
encoding();
for(int i=0; i<times; ++i){
cur = i;
get_fitness();
selection();
pair<double,int>it = get_best();
debug[i] = g[it.second];
debug2[i] = it.first;
crosscover();
mutation();
}
printf("%f\n",debug2[times-1]);
return 0;
}
//模拟退火算法,2.6s
# include <bits/stdc++.h>
using namespace std;
const int num = 34;
double T0 = 18000;
double T1 = 1e-9;
double r = 0.98;
int len = 1000;
double mp[num+3][num+3];
struct node{
double x, y;
}point[num+3];
double dis(int u, int v){
double x = point[u].x-point[v].x;
double y = point[u].y-point[v].y;
return sqrt(x*x+y*y);
}
void init_map(){//初始化边的情况
for(int i=0; i<num; ++i){
scanf("%lf%lf",&point[i].x,&point[i].y);
}
for(int i=0; i<num; ++i){
for(int j=0; j<num; ++j){
mp[i][j] = dis(i,j);
}
}
}
double cal_distance(vector<int>x){//计算染色体的距离
double res = mp[x[0]][x[num-1]];
for(int i=0; i<num-1; ++i)
res += mp[x[i]][x[i+1]];
return res;
}
void change(vector<int>&v){
int x = rand()%num;
int y = rand()%num;
while(y == x) y = rand()%num;
for(int i=0; i+x<=(x+y>>1); ++i)
swap(v[i+x], v[y-i]);
}
int main(){
//freopen("a.txt", "r", stdin);
//reopen("3.txt", "w", stdout);
srand(time(0));
vector<int>ans;
init_map();
int icount = 0, cnt = 0;
for(int i=0; i<num; ++i) ans.push_back(i);
random_shuffle(ans.begin(), ans.end());
while(T0 > T1){
for(int i=0; i<len; ++i){
vector<int>tmp = ans;
change(tmp);
double pre = cal_distance(ans);//前
double cur = cal_distance(tmp);//后
if(cur < pre || exp(-(cur-pre)/T0) > ((double)rand())/RAND_MAX){
ans = tmp;
}
}
++icount;
T0 *= r;
}
printf("run %d %d times\n",icount,cnt);
printf("%f\n",cal_distance(ans));
for(int i:ans) printf("%d ",i);
return 0;
}
//蚂蚁群算法TSP,33s
# include <bits/stdc++.h>
using namespace std;
const int N = 34;
const int M = 700;
double mp[N+3][N+3];
double phe[N+3][N+3];
double phe2[N+3][N+3];
double rate = 0.5;
double Q = 1000;
int path[M+3][N+3]={0};
int alpha = 1;
int beta = 4;
int times = 700;
bool vis[N+3];
struct node{
double x,y;
}point[N+3];
double dis(int u, int v){
double x = point[u].x-point[v].x;
double y = point[u].y-point[v].y;
return sqrt(x*x+y*y);
}
void init_map(){//初始化边的情况
for(int i=0; i<N; ++i){
scanf("%lf%lf",&point[i].x,&point[i].y);
}
for(int i=0; i<N; ++i){
for(int j=0; j<N; ++j){
mp[i][j] = dis(i,j);
}
}
}
double cal_distance(int a[]){
double tot = 0;
for(int i=0; i<N-1; ++i){
tot += mp[a[i]][a[i+1]];
}
tot += mp[a[0]][a[N-1]];
return tot;
}
int main(){
//freopen("a.txt", "r", stdin);
//freopen("4.txt", "w", stdout);
srand(time(0));
init_map();
for(int i=0; i<N; ++i)
for(int j=0; j<N; ++j)
phe[i][j] = 1.0;
for(int T=0; T<times; ++T){
for(int i=0; i<M; ++i){//遍历每个蚂蚁
memset(vis, false, sizeof(vis));
int cur = rand()%N;
vis[cur] = true;
path[i][0] = cur;
for(int j=1; j<N; ++j){
double pob[N+3] = {0}, POB=0;
for(int k=0; k<N; ++k){
if(!vis[k]){
pob[k] = pow(phe[cur][k],alpha)*pow(1.0/mp[cur][k], beta);
POB += pob[k];
}
}
if(POB > 0){
double zhuan = rand()*1.0/RAND_MAX * POB;
for(int k=0; k<N; ++k){
if(!vis[k]){
zhuan -= pob[k];
if(zhuan <= 0 || k==N-1){
cur = k;
break;
}
}
}
}
vis[cur] = true;
path[i][j] = cur;
}
}
memset(phe2, 0, sizeof(phe2));//更新信息素
for(int i=0; i<M; ++i){
double tot = 0;
tot += cal_distance(path[i]);
for(int j=0; j<N-1; ++j){
phe2[path[i][j]][path[i][j+1]] += Q/tot;
phe2[path[i][j+1]][path[i][j]] = phe2[path[i][j]][path[i][j+1]];
}
phe2[path[i][0]][path[i][N-1]] += Q/tot;
phe2[path[i][N-1]][path[i][0]] = phe2[path[i][0]][path[i][N-1]];
}
for(int i=0; i<N; ++i){
for(int j=0; j<N; ++j){
phe[i][j] = phe[i][j]*rate + phe2[i][j];
}
}
}
double imin = 1e18;
int id = 0;
for(int i=0; i<M; ++i){
double tmp = cal_distance(path[i]);
if(tmp < imin) imin = tmp, id = i;
}
printf("%f\n",imin);
for(int i=0; i<N; ++i) printf("%d ",path[id][i]);
return 0;
}
//Hopfield神经网络求解TSP,20s
# include <bits/stdc++.h>
using namespace std;
const int N = 34;
double A = 10000,D = 75, U0 = 0.001, C = N*N;
double mp[N+3][N+3];
double U[(N+3)*(N+3)];
double V[(N+3)*(N+3)];
int id[N+3]={0};
double rnd(){//返回[-1,1]的随机浮点数
return 1.0*rand()/RAND_MAX*2-1;
}
struct node{
double x,y;
}point[N+3];
double dis(int u, int v){
double x = point[u].x-point[v].x;
double y = point[u].y-point[v].y;
return sqrt(x*x+y*y);
}
void init(){//初始化边的情况
for(int i=0; i<N; ++i){
// scanf("%d",&id);
scanf("%lf%lf",&point[i].x,&point[i].y);
}
for(int i=0; i<N; ++i){
for(int j=0; j<N; ++j){
mp[i][j] = dis(i,j);
}
}
}
void update_U(){
double X[N+3] = {0};
double Y[N+3] = {0};
double tot = 0;
for(int i=0; i<N*N; ++i) tot += V[i];
for(int i=0; i<N; ++i){
double sum = 0;
for(int j=0; j<N; ++j)
sum += V[i*N+j];
X[i] = sum;
}
for(int j=0; j<N; ++j){
double sum = 0;
for(int i=0; i<N; ++i)
sum += V[i*N+j];
Y[j] = sum;
}
for(int i=0; i<N; ++i){
for(int j=0; j<N; ++j){
double sum = 0;
for(int k=0; k<N; ++k){
sum += mp[i][k]*V[k*N+(j+1)%N];
}
U[i*N+j] += (-A*(X[i]-1) - A*(Y[j]-1) - D*sum)*0.0001;
}
}
}
void update_V(){
for(int i=0; i<N*N; ++i){
V[i] = 0.5*(1+tanh(U[i]/U0));
}
}
pair<double, vector<int> > check_V(){
set<int>s;
vector<int>g;
double imax[N+3]={0};
for(int i=0; i<N; ++i) imax[i] = -1e18;
for(int j=0; j<N; ++j){
for(int i=0; i<N; ++i){
imax[j] = max(imax[j], V[i*N+j]);
}
}
for(int j=0; j<N; ++j){
for(int i=0; i<N; ++i){
if(V[i*N+j] == imax[j]){
s.insert(i);
g.push_back(i);
break;
}
}
}
double res = 0;
if(s.size() != N) return make_pair(1e18, g);
for(int i=0; i<N; ++i) res += mp[g[i]][g[(i+1)%N]];
return make_pair(res, g);
}
int main(){
//freopen("a.txt", "r", stdin);
//freopen("5.txt", "w", stdout);
srand(time(0));
init();
for(int i=0; i<N*N; ++i) U[i] = 0.5*U0*log(N-1)+rnd();
update_V();
vector<int>bb;
double tmp = 0, ans = 1e18;
int times = 80000;
while(times--){
update_U();
update_V();
auto it = check_V();
if(it.first < ans){
ans = it.first;
bb = it.second;
}
}
printf("%f\n",ans);
for(int i:bb) printf("%d ",i);
return 0;
}
//禁忌搜索,18s
# include <bits/stdc++.h>
using namespace std;
const int N = 34;
const double inf = 1e18;
double mp[N+3][N+3];
int times = 8000;
int len = 12;
vector<vector<int> >jinji;
map<vector<int>,bool>Hash;
struct node{
double x, y;
}point[N+3];
double dis(int u, int v){
double x = point[u].x-point[v].x;
double y = point[u].y-point[v].y;
return sqrt(x*x+y*y);
}
void init(){
for(int i=0; i<N; ++i){
scanf("%lf%lf",&point[i].x,&point[i].y);
}
for(int i=0; i<N; ++i){
for(int j=0; j<N; ++j){
mp[i][j] = dis(i,j);
}
}
}
double cal(vector<int>g){
double res = 0;
for(int i=0; i<N; ++i) res += mp[g[i]][g[(i+1)%N]];
return res;
}
void update(vector<int>g){
if(Hash[g]) return;
jinji.push_back(g);
if(jinji.size() > len){
vector<int>tmp = *jinji.begin();
Hash[tmp]= false;
jinji.erase(jinji.begin());
}
}
int main(){
//freopen("a.txt", "r", stdin);
//freopen("6.txt", "w", stdout);
srand(time(0));
init();
vector<int>ans;
for(int i=0; i<N; ++i) ans.push_back(i);
random_shuffle(ans.begin(), ans.end());
double ans_val = cal(ans);
for(int T=0; T<times; ++T){
double t_val = inf, t_val2 = inf;
vector<int>t_ans, t_ans2;
for(int i=0; i<400; ++i){
vector<int>base = ans;
int x = rand()%N, y = rand()%N;
if(x > y) swap(x, y);
for(int j=0; j<=(y-x>>1); ++j) swap(base[j], base[y-j]);
double tmp = cal(base);
if(tmp < t_val){
t_val = tmp;
t_ans = base;
}
else if(!Hash[base] && tmp < t_val2){
t_val2 = tmp;
t_ans = base;
}
}
if(t_val != inf){
ans = t_ans;
ans_val = t_val;
}
else if(t_val2 != inf){
ans = t_ans2;
ans_val = t_val2;
}
update(ans);
}
printf("%f\n",ans_val);
for(int i:ans) printf("%d ",i);
return 0;
}