在人工智能中对TSP问题的求解

转载:http://blog.csdn.net/zhaoxinfan/article/details/8491389

信学过算法的童鞋都听说过一个很经典的问题:TSP问题,这个问题是NP问题,无法在多项式时间内进行求解。当问题规模较小时,还可以用穷举的方法进行求解,但是当城市一旦变多,穷举的时间将会指数级增加。就算采用启发式搜索,估计也很难求解。

但是这个问题是可以尝试解决的,人工智能给我们提供了强大的武器,也许尽管无法求得全局最优解,但我们也能得到一个很不错的解。最主要的是,我们可以在可以忍耐的时间内得到一个解。下面给出人工智能中对TSP问题求解的几种方法,这也是刘峡壁老师在课堂上反复强调的。

1、使用霍普菲尔德网络求解TSP问题

首先我们要把TSP的图转换为二维矩阵,就像下面这样,这里是一个以城市为元素的矩阵,同时每个元素都对应一个神经网络的神经元:


限制条件是:

  • 每行仅有一个神经元处于活跃状态
  • 每列仅有一个神经元处于活跃状态
  • 对n个城市的问题,需要有n个神经元处于活跃状态
例如针对五个城市,列代表到达某个城市的时间,行代表城市,则可以如下表示:


接下来我们就可以按照霍普菲尔德网络求解的一般做法进行处理,我们可以如下定义能量函数:


然后可以把上面的式子转换为符合二维霍普菲尔德网络的形式:


最后我们只需要随机给定初始值,对神经元进行扰动,当网络能量达到最小时会稳定下来,我们就会得到需要的解,下面是别人针对4个城市的一个求解过程:



2、使用遗传算法求解TSP问题


遗传算法主要有三个操作,选择,交叉和变异。个人觉得在求解TSP问题时,遗传算法的优势就是能在全局和局部直接达到平衡,它不像穷举算法那样耗费很多时间进行全局搜索,而是能较快确定解的范围,当确定范围以后,它又能对局部进行比较细致的搜索,找到一个比较好的解。

全局探索(Exploration):交叉重组与突变是算法全局探测能力的主要构成要素。

局部探测(Exploitation):对种群个体的选择是算法局部探测能力的主要构成要素。

平衡方法主要通过调节各要素的随机变化的参数实现,较大突变概率具有较强的全局探测能力,较大的选择概率意味着较强局部搜索能力。


主要数据结构:

基因表示方法:城市遍历顺序,如G =[1,3,2],表示遍历顺序为1->3->2->1

  1. class Map{  
  2. private:  
  3. int **distance;//用于存储城市之间的距离  
  4. public:  
  5. int Distance(int city_1,city_2);//返回两个城市的距离  
  6. }  
  7. class Population{  
  8. private:  
  9.     int Max_number;  
  10.     int RanParNum;//每次随机选择的父体个数  
  11.     double pro;//变异概率  
  12.     int **GenList;//用于存储所有群体基因  
  13.     int **RandomParent; //用于存储随机选择的父母群体  
  14.     int **BestTwoParentFromRP;//用于存储从RandomParent中选取的最好的两个个体  
  15.     int *NewChild;//用于存储即将进行变异和更新群体的孩子个体  
  16.     int *Solution;  
  17. public:  
  18.     static int GenLen;  
  19.     Population(int m=100,int RPN=5,double p=0.8,int i=0,int **GL=NULL,  
  20.         int **RP=NULL,int **BTPFRP=NULL,int *NC=NULL,int *S=NULL)  
  21.         :Max_number(m),RanParNum(RPN),pro(p),icount(i),  
  22.         GenList(GL),RandomParent(RP),  
  23.         BestTwoParentFromRP(BTPFRP),NewChild(NC),Solution(S){}//构造参数  
  24.     void randominit();//初始化群体及相关参数  
  25.     bool Evlote(int MaxTime);  
  26.     void GetParents();//选取少量个体  
  27.     void SelectBestParent();//从少量个体中选取两个作为父母  
  28.     void ReConbination();//基因重组,并保证子个体是合法的  
  29.     void Swap();//交换变异  
  30.     int Replace();//更新群体  
  31. void Display();//输出状态  
  32.     int fit(int* person);//计算适应度,这里为对应方案的路程的倒数  
  33. };  
  34.   
  35. //主要进化算法:  
  36.         for(i=0;i<MaxTime;i++)//进化过程  
  37.         {  
  38.             GetParents();  
  39.             SelectBestParent();  
  40.             int *AnotherChild = new int[GenLen+1];//用于暂时存储重组后的一个孩子个体,另一个存储在Population的NewChild中,用于即将进行的个体变异  
  41.             ReConbination(&AnotherChild);//重组  
  42.             Swap();//变异  
  43.             Replace();//更新群体  
  44.             for(int i=0;i<=GenLen;i++)//将AnotherChild赋值给NewChild进行个体变异  
  45.             {  
  46.                 NewChild[i]=AnotherChild[i];  
  47.             }  
  48.             delete AnotherChild;  
  49.             Swap();//变异  
  50.             Replace();//更新群体  
  51.         }  

更多内容,请参看这里: https://www.ads.tuwien.ac.at/raidl/tspga/TSPGA.html

3、使用蚁群算法求解TSP问题


对于蚁群算法不想过多说明,具体看这里, Ant colony optimization algorithms  总之你可以小看一只蚂蚁,但不能小看一群蚂蚁,《 哥德尔、艾舍尔、巴赫集异璧之大成》这本奇书中也提到了这一点。

用蚁群求解TSP问题主要是利用蚁周模型,即蚂蚁每完成一次城市的遍历后才更新所有路径上的信息素,求解过程如下:


下面是一个四个城市的例子:

这里共有两只蚂蚁,一只沿着四条边走,另一只沿着对角线走,它们经过的距离肯定是不一样的,由于蚁周模型中信息素的变化是依据下面这个式子:

所以前一只蚂蚁通过后在每条边留下的信息素为1/4=0.25 ;后一只蚂蚁为1/4.8≈0.21
经过叠加以后,上下两条边的信息素得到的加强,相比之下对角线的信息素值最小。随着时间推移和信息素的挥发,信息素值越大的路线上走过的蚂蚁越多,而蚂蚁的增多也促进了信息素的增加,相反信息素值越小将会越来越没有蚂蚁走,最终废弃。针对这个例子,最终的结果就是走正方形的四条边。

[java]  view plain copy print ?
  1. //主要数据结构:  
  2. public class ACO {   
  3.     private Ant[] ants; //蚂蚁  
  4.     private int antNum; //蚂蚁数量  
  5.     private int cityNum; //城市数量  
  6.     private int MAX_GEN; //运行代数  
  7.     private float[][] pheromone; //信息素矩阵  
  8.     private int[][] distance; //距离矩阵  
  9.     private int bestLength; //最佳长度  
  10.     private int[] bestTour; //最佳路径  
  11.       
  12.     //三个参数  
  13.     private float alpha;   
  14.     private float beta;  
  15.     private float rho;  
  16.   
  17.  public void init(String filename);//从文件初始化数据  
  18. }  
  19. //主要算法:  
  20. for (int g = 0; g < MAX_GEN; g++) {  
  21.     //蚂蚁依据信息素寻找解  
  22.     for (int i = 0; i < antNum; i++) {  
  23.         for (int j = 1; j < cityNum; j++) {  
  24.             ants[i].selectNextCity(pheromone);//选择下一个城市,并从禁忌表去除该城市  
  25.         }  
  26.         ants[i].getTabu().add(ants[i].getFirstCity());  
  27.         //更新最好Tour  
  28.         if (ants[i].getTourLength() < bestLength) {  
  29.             bestLength = ants[i].getTourLength();  
  30.             for (int k = 0; k < cityNum + 1; k++) {  
  31.                 bestTour[k] = ants[i].getTabu().get(k).intValue();  
  32.             }  
  33.         }  
  34.         //计算此次释放的信息素  
  35.         for (int j = 0; j < cityNum; j++) {          ants[i].getDelta()[ants[i].getTabu().get(j).intValue()][ants[i].getTabu().get(j+1).intValue()] = (float) (1./ants[i].getTourLength());  
  36.             ants[i].getDelta()[ants[i].getTabu().get(j+1).intValue()][ants[i].getTabu().get(j).intValue()] = (float) (1./ants[i].getTourLength());  
  37.         }  
  38.     }  
  39.   
  40.     //更新信息素  
  41.         //信息素挥发    
  42.         for(int i=0;i<cityNum;i++)    
  43.             for(int j=0;j<cityNum;j++)    
  44.                 pheromone[i][j]=pheromone[i][j]*(1-rho);    
  45.         //信息素更新    
  46.         for(int i=0;i<cityNum;i++){    
  47.             for(int j=0;j<cityNum;j++){    
  48.                 for (int k = 0; k < antNum; k++) {  
  49.                     pheromone[i][j] += ants[k].getDelta()[i][j];  
  50.                 }   
  51.             }    
  52.         }    
  53.   
  54.     //重新初始化蚂蚁  
  55.     for(int i=0;i<antNum;i++){    
  56.         ants[i].init(distance, alpha, beta);    
  57.     }    
  58. }  

同样这里也存在全局和局部搜索问题

全局探索(Exploration):挥发系数(rho)越大;信息素的更新策略越均匀,收敛越慢,全局探索能力越强。

局部探测(Exploitation):与全局探索对应,挥发系数(rho)越小;信息素的更新策略越不均匀,收敛越快,局部探测能力越强。

 

可以使用一些有效的参数和更新策略选取算法,对多组参数和更新策略进行比较、验证,以获得效果理想的参数和更新策略。

更多参看 http://www.cnblogs.com/biaoyu/archive/2012/09/26/2704456.html




小结:以上的三种方法分别对应于人工智能的三个子领域(神经网络,进化计算,群智能),在这里我们能看到使用多种方法求解某一类问题的妙处,这三种方法中究竟哪种方法最好并没有一个权威的论断,不过显然既然是从不同角度出发肯定都有各自的优缺点,难分伯仲。还是要说,人工智能是很有意思的一个领域,这个领域很宽泛,面极其广阔,包含了太多的东西,包括认知科学,机器学习,自然语言处理,机器人学,计算机博弈,自动定理证明,模式识别,计算机视觉等等等等,希望更多的人能涌入这个领域,AI前景无限美好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值