转载:http://blog.csdn.net/zhaoxinfan/article/details/8491389
信学过算法的童鞋都听说过一个很经典的问题:TSP问题,这个问题是NP问题,无法在多项式时间内进行求解。当问题规模较小时,还可以用穷举的方法进行求解,但是当城市一旦变多,穷举的时间将会指数级增加。就算采用启发式搜索,估计也很难求解。
但是这个问题是可以尝试解决的,人工智能给我们提供了强大的武器,也许尽管无法求得全局最优解,但我们也能得到一个很不错的解。最主要的是,我们可以在可以忍耐的时间内得到一个解。下面给出人工智能中对TSP问题求解的几种方法,这也是刘峡壁老师在课堂上反复强调的。
1、使用霍普菲尔德网络求解TSP问题
首先我们要把TSP的图转换为二维矩阵,就像下面这样,这里是一个以城市为元素的矩阵,同时每个元素都对应一个神经网络的神经元:
限制条件是:
- 每行仅有一个神经元处于活跃状态
- 每列仅有一个神经元处于活跃状态
- 对n个城市的问题,需要有n个神经元处于活跃状态
2、使用遗传算法求解TSP问题
全局探索(Exploration):交叉重组与突变是算法全局探测能力的主要构成要素。
局部探测(Exploitation):对种群个体的选择是算法局部探测能力的主要构成要素。
平衡方法主要通过调节各要素的随机变化的参数实现,较大突变概率具有较强的全局探测能力,较大的选择概率意味着较强局部搜索能力。
主要数据结构:
基因表示方法:城市遍历顺序,如G =[1,3,2],表示遍历顺序为1->3->2->1
- class Map{
- private:
- int **distance;//用于存储城市之间的距离
- public:
- int Distance(int city_1,city_2);//返回两个城市的距离
- }
- class Population{
- private:
- int Max_number;
- int RanParNum;//每次随机选择的父体个数
- double pro;//变异概率
- int **GenList;//用于存储所有群体基因
- int **RandomParent; //用于存储随机选择的父母群体
- int **BestTwoParentFromRP;//用于存储从RandomParent中选取的最好的两个个体
- int *NewChild;//用于存储即将进行变异和更新群体的孩子个体
- int *Solution;
- public:
- static int GenLen;
- Population(int m=100,int RPN=5,double p=0.8,int i=0,int **GL=NULL,
- int **RP=NULL,int **BTPFRP=NULL,int *NC=NULL,int *S=NULL)
- :Max_number(m),RanParNum(RPN),pro(p),icount(i),
- GenList(GL),RandomParent(RP),
- BestTwoParentFromRP(BTPFRP),NewChild(NC),Solution(S){}//构造参数
- void randominit();//初始化群体及相关参数
- bool Evlote(int MaxTime);
- void GetParents();//选取少量个体
- void SelectBestParent();//从少量个体中选取两个作为父母
- void ReConbination();//基因重组,并保证子个体是合法的
- void Swap();//交换变异
- int Replace();//更新群体
- void Display();//输出状态
- int fit(int* person);//计算适应度,这里为对应方案的路程的倒数
- };
- //主要进化算法:
- for(i=0;i<MaxTime;i++)//进化过程
- {
- GetParents();
- SelectBestParent();
- int *AnotherChild = new int[GenLen+1];//用于暂时存储重组后的一个孩子个体,另一个存储在Population的NewChild中,用于即将进行的个体变异
- ReConbination(&AnotherChild);//重组
- Swap();//变异
- Replace();//更新群体
- for(int i=0;i<=GenLen;i++)//将AnotherChild赋值给NewChild进行个体变异
- {
- NewChild[i]=AnotherChild[i];
- }
- delete AnotherChild;
- Swap();//变异
- Replace();//更新群体
- }
更多内容,请参看这里: https://www.ads.tuwien.ac.at/raidl/tspga/TSPGA.html
3、使用蚁群算法求解TSP问题
- //主要数据结构:
- public class ACO {
- private Ant[] ants; //蚂蚁
- private int antNum; //蚂蚁数量
- private int cityNum; //城市数量
- private int MAX_GEN; //运行代数
- private float[][] pheromone; //信息素矩阵
- private int[][] distance; //距离矩阵
- private int bestLength; //最佳长度
- private int[] bestTour; //最佳路径
- //三个参数
- private float alpha;
- private float beta;
- private float rho;
- public void init(String filename);//从文件初始化数据
- }
- //主要算法:
- for (int g = 0; g < MAX_GEN; g++) {
- //蚂蚁依据信息素寻找解
- for (int i = 0; i < antNum; i++) {
- for (int j = 1; j < cityNum; j++) {
- ants[i].selectNextCity(pheromone);//选择下一个城市,并从禁忌表去除该城市
- }
- ants[i].getTabu().add(ants[i].getFirstCity());
- //更新最好Tour
- if (ants[i].getTourLength() < bestLength) {
- bestLength = ants[i].getTourLength();
- for (int k = 0; k < cityNum + 1; k++) {
- bestTour[k] = ants[i].getTabu().get(k).intValue();
- }
- }
- //计算此次释放的信息素
- 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());
- ants[i].getDelta()[ants[i].getTabu().get(j+1).intValue()][ants[i].getTabu().get(j).intValue()] = (float) (1./ants[i].getTourLength());
- }
- }
- //更新信息素
- //信息素挥发
- for(int i=0;i<cityNum;i++)
- for(int j=0;j<cityNum;j++)
- pheromone[i][j]=pheromone[i][j]*(1-rho);
- //信息素更新
- for(int i=0;i<cityNum;i++){
- for(int j=0;j<cityNum;j++){
- for (int k = 0; k < antNum; k++) {
- pheromone[i][j] += ants[k].getDelta()[i][j];
- }
- }
- }
- //重新初始化蚂蚁
- for(int i=0;i<antNum;i++){
- ants[i].init(distance, alpha, beta);
- }
- }
同样这里也存在全局和局部搜索问题
全局探索(Exploration):挥发系数(rho)越大;信息素的更新策略越均匀,收敛越慢,全局探索能力越强。
局部探测(Exploitation):与全局探索对应,挥发系数(rho)越小;信息素的更新策略越不均匀,收敛越快,局部探测能力越强。
可以使用一些有效的参数和更新策略选取算法,对多组参数和更新策略进行比较、验证,以获得效果理想的参数和更新策略。
更多参看 http://www.cnblogs.com/biaoyu/archive/2012/09/26/2704456.html