您的位置:首页 > 其它

模拟退火算法求解TSP

2016-05-11 21:23 399 查看
算法背景,伪代码请参考博客/article/6967253.html

算法思想,模拟物理的退火过程。区别于爬山算法的关键在于,对于比当前差的解,不是直接舍弃,而是以一定的概率接受。

(主要框架:三个函数+两个准则)

给定初温t=t0,随机产生初始状态s=s0,令k=0;

Repeat

Repeat

产生新状态sj=Genete(s)

if min{1,exp[-(C(sj)-C(s))/tk]}>=randrom[0,1] s=sj;

Until 抽样稳定准则满足;

退温tk+1=update(tk)并令k=k+1;

Until算法终止准则满足;

输出算法搜索结果。

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <fstream>
#define CITYNUM 52
#define MAX 0x7fffffff
using namespace std;
struct Point
{
    int x;
    int y;
    char name;
};
//read the graph & compute the distance dist[i][j]
void InitGraph(double dist[CITYNUM][CITYNUM],Point citys[CITYNUM])
{
    fstream fileRead;
    fileRead.open("coords.txt",ios::in);
    for(int i=0;i<CITYNUM;i++)
    {
        int temp;
        char ch;
        fileRead>>temp>>ch>>citys[i].x>>ch>>citys[i].y>>ch>>citys[i].name;
        //cout<<temp<<ch<<citys[i].x<<ch<<citys[i].y<<ch<<citys[i].name<<endl;
    }
    fileRead.close();
    for(int i=0;i<CITYNUM;i++)
    {
        for(int j=0;j<CITYNUM;j++)
        {
            if(j!=i&&dist[i][j]==0)
            {
                double d2=(citys[i].x-citys[j].x)*(citys[i].x-citys[j].x)+(citys[i].y-citys[j].y)*(citys[i].y-citys[j].y);
                dist[i][j]=dist[j][i]=sqrt(d2);
            }
        }
    }
}
double Evalue(const vector<int> answer,double dist[CITYNUM][CITYNUM])
{
    double sum=0;
    for(int i=0;i<answer.size()-1;i++)
    {
        //cout<<answer[i]<<"->"<<answer[i+1]<<":"<<sum<<"+"<<dist[answer[i]][answer[i+1]]<<"="<<sum+dist[answer[i]][answer[i+1]]<<endl;
        sum+=dist[answer[i]][answer[i+1]];
    }
    sum+=dist[answer[answer.size()-1]][answer[0]];
    return sum;
}
void Swap(vector<int> &newAnswer,int first,int second)
{
    newAnswer[first]=newAnswer[first]^newAnswer[second];
    newAnswer[second]=newAnswer[first]^newAnswer[second];
    newAnswer[first]=newAnswer[first]^newAnswer[second];
}
void Reverse(vector<int> &newAnswer,int first,int second)
{
    if(first>second)
    {
        first=first^second;
        second=first^second;
        first=first^second;
    }
    reverse(newAnswer.begin()+first,newAnswer.begin()+second);
}
void Save(const vector<int> minAnswer,Point citys[CITYNUM],double t0,double alpha,double te,double minSum)
{
    fstream fileWrite;
    fileWrite.open("out.txt",ios::out|ios::app);
    fileWrite<<"起始温度:"<<t0<<",终止温度:"<<te<<",降温系数:"<<alpha<<",近似最优:"<<minSum<<endl;
    for(int i=0;i<minAnswer.size();i++)
    {
        fileWrite<<citys[minAnswer[i]].name<<"->";
    }
    fileWrite<<citys[minAnswer[0]].name<<endl;
    fileWrite.close();
}
void SimuAnne(double t0,double alpha,double te )
{
    vector<int> answer,newAnswer,minAnswer;
    int k=0;//记录循环次数
    double t=t0;
    double sumDist=0,newSum=0,minSum=MAX;
    double dist[CITYNUM][CITYNUM]={0};
    Point citys[CITYNUM];//city's coordinate
    InitGraph(dist,citys);
    //initial answer
    for(int i=0;i<CITYNUM;i++)
    {
        answer.push_back(i);
    }
    srand ( unsigned (time(0) ) );
    random_shuffle(answer.begin(),answer.end());
    sumDist=Evalue(answer,dist);
    minSum=sumDist;
    minAnswer.assign(newAnswer.begin(),newAnswer.end());
    cout<<k<<" "<<minSum<<endl;
    copy(answer.begin(),answer.end(),ostream_iterator<int>(cout," "));cout<<endl;//输出answer
    while(t>te)
    {
        //srand ( unsigned (time(0) ) );
        newAnswer.assign(answer.begin(),answer.end());
        int first=0,second=0;
        //swap first & second
        first=rand()%CITYNUM;
        second=rand()%CITYNUM;
        if(first!=second)
        {
            //cout<<first<<"--"<<second<<endl;
            Swap(newAnswer,first,second);//产生新的状态
            //Reverse(newAnswer,first,second);//产生新的状态
            newSum=Evalue(newAnswer,dist);
            if(min(1.0,exp(-(newSum-sumDist)/t))>=(rand()%998)/997.0)
            {
                answer.assign(newAnswer.begin(),newAnswer.end());
                sumDist=newSum;
                if(newSum<minSum)
                {
                    minSum=newSum;
                    minAnswer.assign(newAnswer.begin(),newAnswer.end());
                    cout<<k<<" "<<minSum<<endl;
                    copy(answer.begin(),answer.end(),ostream_iterator<int>(cout," "));cout<<endl;//输出answer
                }
                k++;
            }
            t=t*alpha;
        }
    }
    Save(minAnswer,citys,t0,alpha,te,minSum);
    for(int i=0;i<minAnswer.size();i++)
    {
        cout<<citys[minAnswer[i]].name<<"->";
    }
    cout<<citys[minAnswer[0]].name<<endl;
}
int main()
{
    double t0=1000;//起始温度
    double alpha=0.999999;//降温系数
    double te=0.000001;//截止温度
    SimuAnne(t0,alpha,te);
    return 0;
}


测试数据:

0,1,1,a
1,1,2,b
2,1,3,c
3,1,4,d
4,1,5,e
5,1,6,f
6,1,7,g
7,1,8,h
8,1,9,i
9,1,10,j
10,2,11,k
11,7,11,l
12,12,11,m
13,17,11,n
14,22,11,o
15,27,11,p
16,32,11,q
17,37,11,r
18,42,11,s
19,47,11,t
20,52,11,u
21,57,11,v
22,62,11,w
23,67,11,x
24,72,11,y
25,77,11,z
26,82,11,A
27,87,11,B
28,92,11,C
29,97,11,D
30,101,10,E
31,101,9,F
32,101,8,G
33,101,7,H
34,101,6,I
35,101,5,J
36,101,4,K
37,101,3,L
38,101,2,M
39,100,1,N
40,95,1,O
41,90,1,P
42,85,1,Q
43,80,1,R
44,75,1,S
45,70,1,T
46,65,1,U
47,60,1,V
48,55,1,W
49,50,1,X
50,45,1,Y
51,40,1,Z


以上算法,循环次数比较多。跟蚁群算法一比被虐成渣(有兴趣的话可以留言交流)。

起始温度:1e+007,终止温度:1e-006,降温系数:0.999999,近似最优:228.351
t->s->r->q->p->o->n->j->i->h->g->f->e->d->c->b->a->k->l->m->Z->Y->X->W->V->U->T->S->R->Q->P->O->N->M->L->K->J->I->H->G->F->E->D->C->B->A->z->y->x->w->v->u->t
起始温度:1000,终止温度:1e-006,降温系数:0.999999,近似最优:225.017
T->U->V->W->X->Y->Z->q->p->o->a->b->c->d->e->f->g->h->i->j->k->l->m->n->r->s->t->u->v->w->x->y->z->A->B->C->D->E->F->G->H->I->J->K->L->M->N->O->P->Q->R->S->T
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: