相信学过算法的童鞋都听说过一个很经典的问题:TSP问题,这个问题是NP问题,无法在多项式时间内进行求解。当问题规模较小时,还可以用穷举的方法进行求解,但是当城市一旦变多,穷举的时间将会指数级增加。就算采用启发式搜索,估计也很难求解。
但是这个问题是可以尝试解决的,人工智能给我们提供了强大的武器,也许尽管无法求得全局最优解,但我们也能得到一个很不错的解。最主要的是,我们可以在可以忍耐的时间内得到一个解。下面给出人工智能中对TSP问题求解的几种方法,这也是刘峡壁老师在课堂上反复强调的。
首先我们要把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();//更新群体 }
//主要数据结构: 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