zoukankan      html  css  js  c++  java
  • 蚁群算法求解迷宫最优路径问题

    本段程序的基本思想是利用蚁群算法中的蚁周模型,来对全局的迷宫图进行信息素的跟新

    和为每一仅仅蚂蚁选择下一个方格。 一共会进行RcMax = 2000轮模拟(理论上模拟的次数越多结果

    会越接近真实值)。而在每一轮中会排除 M = 10仅仅蚂蚁进行探路。同一时候在算法的回溯思想上採用的

    是栈的数据结构来实现的。当栈终于为空时则表示无解。但同一时候这段程序的一缺点就是:因为我没在

    算法中对每一轮的每仅仅探路蚂蚁採用多线程的模式,所以总体的执行效率还不是非常高。

    如读者有好的

    思想或建议,请留言。

    #include<iostream>
    #include<stack>
    #include<bitset>
    using namespace std;
    //坐标类
    struct Point
    {
    	int x;
    	int y;
    };
    //地图类
    template<int A,int B>
    class Map
    {
    public:
    	int (*p)[B];//1表示为障碍方格。0表示该方格可通
    	bitset<4> (*around)[B];//记录每个方格四周四个方法的可选标记
    	int row;//行数
    	int col;//列数
    	Map()
    	{
    		p =new int[A][B];
    		around = new bitset<4>[A][B];
    	}
    	Map(Map<A,B> & B1)
    	{
    	 p =new int[A][B];
    	 around = new bitset<4>[A][B];
    	 row = B1.row;
    	 col = B1.col;
    	 for(int i = 0;i<row;i++)
    	 {
    		 for(int j = 0;j<col;j++)
    		 {
    			 p[i][j] = B1.p[i][j];
    			 around[i][j] = B1.around[i][j];
    		 }
    	 }
    	}
    	Map<A,B> & operator=(Map<A,B> & B1)
    	{
    	 row = B1.row;
    	 col = B1.col;
    	 for(int i = 0;i<row;i++)
    	 {
    		 for(int j = 0;j<col;j++)
    		 {
    			 this->p[i][j] = B1.p[i][j];
    			 around[i][j] = B1.around[i][j];
    		 }
    	 }
    	 return *this;
    	}
    };
    
    //start起始点, end终止点
    template<int A,int B>
    bool FindPath(Map<A,B> & map,Point & start,Point & end)
    {
    	const int N1 =  A;
    	const int N2 =  B;
    	
    	const int M = 10;//每一轮中蚂蚁的个数
    	const int RcMax = 2000;//迭代次数
    	const int IN = 1;//信息素的初始量
    
    	double add[N1][N2];//每一段的信息素增量数组
    	double phe[N1][N2];//每一段路径上的信息素
    	double MAX = 0x7fffffff;
    
    	double alphe,betra,rout,Q;//alphe信息素的影响因子,betra路线距离的影响因子,rout信息素的保持度,Q用于计算每仅仅蚂蚁在其路迹留下的信息素增量
    	double bestSolution = MAX;//最短距离
    	stack<Point> Beststackpath;//最优路线
    
    	//初始化变量參数和信息数组
    	alphe = betra = 2;
    	rout = 0.7;
    	Q = 10;
    
    	//先给图的外围加上障碍
    	for(int i = 0;i<map.col;i++)
    	{
    		map.p[0][i] = map.p[map.row-1][i] = 1;
    	}
    	for(int i = 0;i<map.row;i++)
    	{
    		map.p[i][0] = map.p[i][map.col-1] = 1;
    	}
    	//初始化图中每个方格的四周訪问表示位,0表示可訪问
    	//初始化信息素数组
    	for(int i = 0;i<N1;i++ )
    	{
    	 for(int j = 0;j<N2;j++)
    	 {
    		phe[i][j] = IN;
    		map.around[i][j].reset();//4个方向所有设为可选
    	 }
    	}
    
    	//用于方向选择的偏移量数组   依照顺时针的方向
    	Point offset[4];
    	offset[0].x = 0; offset[0].y = 1;//向右
    	offset[1].x = 1; offset[1].y = 0;//向下
    	offset[2].x = 0; offset[2].y = -1;//向左
    	offset[3].x = -1; offset[3].y = 0;//向上
    	
    	//每轮M仅仅蚂蚁,每一轮结束后才进行全局信息素更新
    	stack<Point> stackpath[M];
    	//拷贝障碍地图
    	Map<A,B> Ini_map[M];
    	//记录每一仅仅蚂蚁的当前位置
    	Point Allposition[M];
    
    	int s = 0;
    	while(s<RcMax)//一共RcMax轮
    	{
    
    	//先清空每一仅仅蚂蚁的路线存储栈
    	for(int i = 0;i<M;i++)
    	{
    		while (!stackpath[i].empty())
    		{
    			stackpath[i].pop();
    		}
    	}
    	for(int i = 0;i<M;i++)
    	{
    		Ini_map[i] = map;
    		//将起点初始化为障碍点
    	    Ini_map[i].p[start.x][start.y] = 1;
    		//起点入栈
    	    stackpath[i].push(start);
    		//初始化每一仅仅蚂蚁的当前位置
    		Allposition[i] = start;
    	}
    	
    	//开启M仅仅蚂蚁循环
    	 for(int j = 0;j<M;j++)
    	 {
    		 while(((Allposition[j].x)!=(end.x)||(Allposition[j].y)!=(end.y)))
    		 {
    	       //选择下一步
    		   double psum = 0;
    		   for(int op = 0;op<4;op++)
    		  {
    			//计算下一个可能的坐标
    			int x =  Allposition[j].x + offset[op].x;
    			int y =  Allposition[j].y + offset[op].y;
    			
    		  if((Ini_map[j].around[ Allposition[j].x][Allposition[j].y])[op]==0 && Ini_map[j].p[x][y] !=1)
    		  {
    			  psum += pow(phe[x][y],alphe) * pow((10.0/stackpath[j].size()),betra);
    		  }
    		  }
    		  //推断是否有选择
    		  //如找到了下一点
    		  if(psum!=0)
    		  {
    		  double drand = (double)(rand())/(RAND_MAX+1);
    		  double pro = 0;
    		  int re;
    		  int x,y;
    		  for( re = 0;re<4;re++)
    		  {
    		    //计算下一个可能的坐标
    			 x =  Allposition[j].x + offset[re].x;
    			 y =  Allposition[j].y + offset[re].y;
    		     if((Ini_map[j].around[ Allposition[j].x][Allposition[j].y])[re]==0 &&Ini_map[j].p[x][y]!=1)
    			 {
    			  pro += (pow(phe[x][y],alphe) * pow((10.0/stackpath[j].size()),betra))/psum;
    			  if(pro>=drand)
    			  {
    			  break;
    			  }
    			 }
    		  }
    
    		   //入栈
    		   Allposition[j].x = x;
    		   Allposition[j].y = y;
    		   stackpath[j].push(Allposition[j]);
    		   //设置障碍
    		   Ini_map[j].p[Allposition[j].x][Allposition[j].y] = 1;
    
    		  }
    		  else//没找到了下一点
    		  {   
    			  //向后退一步,出栈
    			  stackpath[j].pop();
    			  //消除入栈时设置的障碍
    			  Ini_map[j].p[Allposition[j].x][Allposition[j].y] = 0;
    			  if(stackpath[j].empty())
    			  {
    				  return false;
    			  }
    			  //设置回溯后的Allposition
    			  if(Allposition[j].x == stackpath[j].top().x)
    			  {
    				  if((Allposition[j].y - stackpath[j].top().y)==1)//向右
    				  {
    					  (Ini_map[j].around[ stackpath[j].top().x][stackpath[j].top().y])[0] = 1;//标记该方向已訪问
    				  }
    				  if((Allposition[j].y - stackpath[j].top().y)==-1)//向左
    				  {
    					  (Ini_map[j].around[ stackpath[j].top().x][stackpath[j].top().y])[2] = 1;//标记该方向已訪问
    				  }
    			  }
    			  if(Allposition[j].y == stackpath[j].top().y)
    			  {
    			  
    				  if((Allposition[j].x - stackpath[j].top().x)==1)//向下
    				  {
    					  (Ini_map[j].around[ stackpath[j].top().x][stackpath[j].top().y])[1] = 1;//标记该方向已訪问
    				  }
    				   if((Allposition[j].x - stackpath[j].top().x)==-1)//向上
    				  {
    					  (Ini_map[j].around[ stackpath[j].top().x][stackpath[j].top().y])[3] = 1;//标记该方向已訪问
    				  }
    			  }
    			  Allposition[j].x = stackpath[j].top().x;
    			  Allposition[j].y = stackpath[j].top().y;
    		  }
    
    	 }
    	 }
    	
    	//保存最优路线
    	double solution = 0;
    	for(int i = 0;i<M;i++)
    	{
    		solution = 0;
    		solution = stackpath[i].size();
    		if(solution<bestSolution)
    		{
    		 Beststackpath = stackpath[i];
    		 bestSolution = solution;
    		}
    	}
    	//计算每一仅仅蚂蚁在其每一段路径上留下的信息素增量
    	//初始化信息素增量数组
    	for(int i = 0;i<N1;i++)
    	{
    	 for(int j = 0;j<N2;j++)
    	 {
    	  add[i][j] = 0;
    	 }
    	}
    
    	for(int i = 0;i<M;i++)
    	{
    	 //先算出每仅仅蚂蚁的路线的总距离solu
    	 double solu = 0;
    	 solu = stackpath[i].size();
    	 double d = Q/solu;
    	 while(!stackpath[i].empty())
    	 {
    		 add[stackpath[i].top().x][stackpath[i].top().y] += d;
    		 stackpath[i].pop();
    	 }
    	}
    	//更新信息素
    	for(int i=0;i<N1;i++)
    	{
    	 for(int j = 0;j<N2;j++)
    	 {
    		 phe[i][j] = phe[i][j]*rout + add[i][j];
    		 //为信息素设置一个下限值和上限值
    		if(phe[i][j]<0.0001)
    		{
    			phe[i][j] = 0.0001;
    		}
    		if(phe[i][j]>20)
    		{
    			phe[i][j] = 20;
    		}
    	 }
    	}
    
    	s++;
    	}//轮
    
    	//找到路径,并输出stackpath
    	cout<<"找到最优路径!"<<endl;
    	cout<<"最短路线长度为: 共"<<Beststackpath.size()<<"个方格!"<<endl;
    	while(!Beststackpath.empty())
    	{
    		cout<<"<"<<Beststackpath.top().x<<","<<Beststackpath.top().y<<">"<<endl;
    		Beststackpath.pop();
    	}
    
    	return true;
    }
    
    int main()
    {
    	//建立迷宫
    	Map<10,10> map;
    	map.col = map.row = 10;
    	int p[10][10];
    	for(int i =0;i<10;i++)//初始化迷宫
    	{
    	 for(int j=0;j<10;j++)
    	 {
    		 p[i][j] = 0;
    	 }
    	}
    	//为迷宫设置障碍
    	p[1][3] = 1;p[1][7] = 1;p[2][3] = 1;p[2][7] = 1;
    	p[3][5] = 1;p[3][6] = 0;p[4][2] = 1;p[4][3] = 1;
    	p[4][4] = 1;p[5][4] = 1;p[6][2] = 1;p[6][6] = 1;
    	p[7][2] = 1;p[7][3] = 1;p[7][4] = 1;p[7][6] = 1;
    	p[8][1] = 1;
    	map.p = p ;
    	Point start,end;
    	start.x = start.y = 1;
    	end.x =8,end.y = 8;
    	if(!FindPath<10,10>(map,start,end))
    	{
    	  cout<<"该迷宫无解!"<<endl;
    	}
    }


  • 相关阅读:
    常用shell
    JavaScript基础
    CSS动画-页面特效
    CSS3常用操作
    CSS3的盒子模型
    CSS定位
    JQuery中的DOM操作
    [单词用法总结]-as
    JQuery选择器
    css选择器
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/7389474.html
Copyright © 2011-2022 走看看