user-0 提问: 一个简单路径问题，求算法实现

回复:
user: user-0
content: 还是递归读着舒服一些，楼上的代码我没具体测试，有点对不住了。 主要是由于我没有说明白需求，在测试的时候漏了几种情况，再开一贴，欢迎各位大大莅临指导~~   以我目前的需求，肯定会漏掉 漏了这么一种情况：  1 1 1 1 0  1 1 1 0 0  1 1 0 0 0  1 0 0 0 0  0 0 0 0 0

user: user-1
content: 引用 4 楼 BreathOfDeath 的回复:不能走斜线。。  那你第一个例子是怎么走出来的？

user: user-0
content: 不可以走已经经过的位置，需求说的不是很明白。 。

user: user-0
content: 不能走斜线。。

user: user-1
content: 能否走斜线？

user: user-2
content: 有没说明白的地方，例如，棋子从a点走到b点再从b点走到a点，如此4步形成的路径可以吗？

user: user-0
content: 沙发，上面的起始点为： 00000000 00111100 00011100 00010000

user: user-2
content: 引用 12 楼 BreathOfDeath 的回复:[quote=引用 7 楼 uuuououlcz 的回复:] [quote=引用 5 楼 BreathOfDeath 的回复:] 不可以走已经经过的位置，需求说的不是很明白。 。  那就是经典回溯了呀，不用递归的话就用stack模拟递归就好了嘛，对于n比较小的时候（就像你这个n = 4的时候），n重for循环也可以[/quote]   递归来一个[/quote]  貌似不用得到全部路径，只要求多少条路径，那上面的就可以剩下path的复制环节了，allPath也可以不要了，给backtrace传个int& count就行了

user: user-2
content: 嗯，没测试，算是个参考吧  #include <cstring> #include <vector> #include <utility> using namespace std; #define MAX 20  /*   coordinate   0------------>X   |   |   |   |   |   Y */  const int stepKind = 4;                                 //how many kinds of steps const int step[][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};   //all kinds of steps, step[i][0] is dy while step[i][1] is dx  int row, col;                           //row and column of the board int board[MAX][MAX];                    //state of each position, whether can be passed by bool vis[MAX][MAX];                     //whether the position has been passed by in a path  /**************************************************   whether the position is legal **************************************************/ inline bool outOfBorder(int y, int x) {     return y < 0 || y >= row || x < 0 || x >= col; } /**************************************************   sy is the y coordinate of the start   sx is the x coordinate of the start   stepLeft is the number of steps to move   allPath will contain all possible path, in which pair.first is y while pair.second is x **************************************************/ void backtrace(int sy, int sx, int stepLeft, vector<pair<int,int> >& path, vector<vector<pair<int,int> > >& allPath) {     if(stepLeft <= 0){         allPath.push_back(path);         return;     }      --stepLeft;      int y, x, i;     for(i = 0; i < stepKind; ++i){         y = sy + step[i][0];         x = sx + step[i][1];         if(!outOfBorder(y, x) && !vis[y][x] && board[y][x] == 1){//can move to this position             path.push_back(make_pair(y, x));            //move one step             vis[y][x] = true;                           //mark new position visited             backtrace(y, x, stepLeft, path, allPath);   //search following steps             path.pop_back();                            //cancel move             vis[y][x] = false;                          //cancel mark         }     } } /**************************************************   sy is the start's y coordinate   sx is the start's x coordinate   steps is the number of steps to move   allPath will hold all possible paths   return the number of paths ***************************************************/ int getAllPath(int sy, int sx, int steps, vector<vector<pair<int,int> > >& allPath) {     //initialize     memset(vis, false, sizeof(vis));     allPath.clear();      vector<pair<int,int> > path;     path.push_back(make_pair(sy, sx));     vis[sy][sx] = true;      //search path     backtrace(sy, sx, steps, path, allPath);     return allPath.size(); }

user: user-0
content: 好强大的代码，多谢啦。

user: user-1
content: //可以把mapping函数修改一下，添加一个步数参数： void mapping(const bool * map,  	int map_width, int map_height,   	int x0, int y0,          size_t steps, 	std::vector<std::vector<std::pair<int, int> > > & routes) {     //...     assert(steps > 0);     //...      //for (size_t i = 0; i < 3; i++)     for (size_t i = 0; i < steps - 1; i++)     //... }  //main函数中调用部分可做相应修改

user: user-1
content: #include <cstdio> #include <assert.h>  #include <vector> #include <algorithm>  /**  * 计算4步路径所有可能  * @param map 			二值地图，true表示通行，false表示障碍，原点在左上角   * @param map_width 	地图宽度  * @param map_height 	地图高度  * @param x0 			初始位置横坐标  * @param y0 			初始位置纵坐标  * @param routes 		返回所有可能的路径   */  void mapping(const bool * map,  	int map_width, int map_height,   	int x0, int y0,  	std::vector<std::vector<std::pair<int, int> > > & routes) { 	assert(map != NULL); //map不可为空  	assert(map_width > 0 && map_height > 0); //长宽不可为空  	assert(x0 >= 0 && x0 < map_width); //初始点横坐标不可越界  	assert(y0 >= 0 && y0 < map_height); //初始点纵坐标不可越界  	 	assert(map[y0 * map_width + x0]); //初始点应属于可通行点 	 	//上、左、下、右四个方向偏移 	int x_4[] = { 0, -1, 0, 1 }, y_4[] = { -1, 0, 1, 0 };  	int x, y; 	 	typedef std::vector<std::pair<int, int> > route_type; 	typedef std::vector<route_type> 		  route_list; 	 	routes.clear(); 	 	//初始只含有一个长为1的路径 （仅含起始点）  	routes.push_back(route_type(1, std::make_pair(x0, y0)));  	//经过3次遍历扩展，每次扩展根据上一次结果寻找下一步路径  	for (size_t i = 0; i < 3; i++) 	{         size_t k = routes.size();  		// 遍历上一次寻路结果  		for (size_t m = 0; m < k; m++) 		{ 			// 4个方向寻找可行的路径  			for (int j = 0; j < 4; j++) 			{ 				// 取最后一个点为起始点进行偏移  				x = routes[m][i].first + x_4[j]; 				y = routes[m][i].second + y_4[j]; 				 				// 判定移动到的点有效  				if (x >= 0 && y >= 0 && x < map_width && y < map_height &&  					map[y * map_width + x]) 				{ 					// 判定未曾走过	 					if (std::find(routes[m].begin(), routes[m].end(),  							std::make_pair(x, y)) == routes[m].end()) 					{  						// 依据上次寻路结果加上本次可通行点形成一个新的路径  						route_type route(routes[m]); 						route.push_back(std::make_pair(x, y)); 						 						// 添加到寻路结果中  						routes.push_back(route); 					} 				}				 			} 		} 		 		// 删除上次寻路结果  		routes.erase(routes.begin(), routes.begin() + k); 	}  }  int main(int argc, char * argv[]) { 	bool map[25] = {true, true, true, true, false,                     true, true, true, false, false,                     true, true, false, false, false,                     true, false, false, false, false,                     false, false, false, false, false                    };    	printf("------- map --------\n"); 	for (size_t m = 0; m < 5; ++m) 	{ 		for (size_t n = 0; n < 5; ++n) 		{ 			printf("%d ", map[m * 5 + n]); 		} 		printf("\n"); 	}	 		     std::vector<std::vector<std::pair<int, int> > > vec;     mapping(map, 5, 5, 0, 0, vec);  	printf("------- routes -------\n");     for (size_t i = 0; i < vec.size(); ++i) 	{ 		int map_tmp[25] = {0}; 		 		for (size_t m = 0; m < 25; ++m) 		{ 			map_tmp[m] = map[m] ? 1 : 0; 		}	 		 		printf("route:%d\n", i); 		for (size_t j = 0; j < vec[i].size(); ++j) 		{ 			map_tmp[vec[i][j].second * 5 + vec[i][j].first] = 2;	 		} 		 		for (size_t m = 0; m < 5; ++m) 		{ 			for (size_t n = 0; n < 5; ++n) 			{ 				printf("%c ",  					map_tmp[m * 5 + n] == 0 ? '0' :  					map_tmp[m * 5 + n] == 1 ? '1' : '*'); 			} 			printf("\n"); 		} 	}  	return 0; }    运行结果： ------- map -------- 1 1 1 1 0  1 1 1 0 0  1 1 0 0 0  1 0 0 0 0  0 0 0 0 0  ------- routes ------- route:0 * 1 1 1 0  * 1 1 0 0  * 1 0 0 0  * 0 0 0 0  0 0 0 0 0  route:1 * 1 1 1 0  * 1 1 0 0  * * 0 0 0  1 0 0 0 0  0 0 0 0 0  route:2 * * 1 1 0  * * 1 0 0  1 1 0 0 0  1 0 0 0 0  0 0 0 0 0  route:3 * 1 1 1 0  * * 1 0 0  1 * 0 0 0  1 0 0 0 0  0 0 0 0 0  route:4 * 1 1 1 0  * * * 0 0  1 1 0 0 0  1 0 0 0 0  0 0 0 0 0  route:5 * * 1 1 0  * * 1 0 0  1 1 0 0 0  1 0 0 0 0  0 0 0 0 0  route:6 * * 1 1 0  1 * 1 0 0  1 * 0 0 0  1 0 0 0 0  0 0 0 0 0  route:7 * * 1 1 0  1 * * 0 0  1 1 0 0 0  1 0 0 0 0  0 0 0 0 0  route:8 * * * 1 0  1 1 * 0 0  1 1 0 0 0  1 0 0 0 0  0 0 0 0 0  route:9 * * * * 0  1 1 1 0 0  1 1 0 0 0  1 0 0 0 0  0 0 0 0 0

user: user-0
content: 引用 7 楼 uuuououlcz 的回复:[quote=引用 5 楼 BreathOfDeath 的回复:] 不可以走已经经过的位置，需求说的不是很明白。 。  那就是经典回溯了呀，不用递归的话就用stack模拟递归就好了嘛，对于n比较小的时候（就像你这个n = 4的时候），n重for循环也可以[/quote]   递归来一个

user: user-0
content: bool map[25] = {true, true, true, true, false,                     true, true, true, false, false,                     true, true, false, false, false,                     true, false, false, false, false,                     false, false, false, false, false                    };      std::vector<std::vector<std::pair<int, int> > > vec;     mapping(map, 5, 5, 0, 0, vec);   结果不是预期的

user: user-3
content: 难道BFS不可以吗？ 没仔细看需求

user: user-1
content: 修正了一点问题：   #include <iostream> #include <vector>   /**  * 计算4步路径所有可能  * @param map 			二值地图，true表示通行，false表示障碍，原点在左上角   * @param map_width 	地图宽度  * @param map_height 	地图高度  * @param x0 			初始位置横坐标  * @param y0 			初始位置纵坐标  * @param routes 		返回所有可能的路径   */  void mapping(const bool * map,  	int map_width, int map_height,   	int x0, int y0,  	std::vector<std::vector<std::pair<int, int> > > & routes) { 	assert(map != NULL); //map不可为空  	assert(map_width > 0 && map_height > 0); //长宽不可为空  	assert(x0 >= 0 && x0 < map_width); //初始点横坐标不可越界  	assert(y0 >= 0 && y0 < map_height); //初始点纵坐标不可越界  	 	assert(map[x0 * map_width + y0]); //初始点应属于可通行点 	 	//上、左、下、右四个方向偏移 	int x_4[] = { 0, -1, 0, 1 }, y_4[] = { -1, 0, 1, 0 };  	int x, y; 	 	typedef std::vector<std::pair<int, int> > route_type; 	typedef std::vector<route_type> 		  route_list; 	 	routes.clear(); 	 	//初始只含有一个长为1的路径 （仅含起始点）  	routes.push_back(route_type(1, std::make_pair(x0, y0)));  	//经过3次遍历扩展，每次扩展根据上一次结果寻找下一步路径  	for (size_t i = 0, k = routes.size(); i < 3; i++) 	{ 		// 遍历上一次寻路结果  		for (size_t m = 0; m < k; m++) 		{ 			// 4个方向寻找可行的路径  			for (int j = 0; j < 4; j++) 			{ 				// 取最后一个点为起始点进行偏移  				x = routes[m][i].first + x_4[j]; 				y = routes[m][i].second + y_4[j]; 				 				// 判定移动到的点有效  				if (x >= 0 && y >= 0 && x < map_width && y < map_height &&  					map[x * map_width + y]) 				{ 					// 判定未曾走过	 					if (std::find(routes[m].begin(), routes[m].end(),  							std::make_pair(x, y)) == routes[m].end()) 					{  						// 依据上次寻路结果加上本次可通行点形成一个新的路径  						route_type route(routes[m]); 						route.push_back(std::make_pair(x, y)); 						 						// 添加到寻路结果中  						routes.push_back(route); 					} 				}				 			} 		} 		 		// 删除上次寻路结果  		routes.erase(routes.begin(), routes.begin() + k); 	}  }

user: user-1
content: 没有数据测试，你试下。  #include <iostream> #include <vector>   /**  * 计算4步路径所有可能  * @param map 			二值地图，true表示通行，false表示障碍，原点在左上角   * @param map_width 	地图宽度  * @param map_height 	地图高度  * @param x0 			初始位置横坐标  * @param y0 			初始位置纵坐标  * @param routes 		返回所有可能的路径   */  void mapping(const bool * map,  	int map_width, int map_height,   	int x0, int y0,  	std::vector<std::vector<std::pair<int, int> > > & routes) { 	assert(map != NULL); //map不可为空  	assert(map_width > 0 && map_height > 0); //长宽不可为空  	assert(x0 >= 0 && x0 < map_width); //初始点横坐标不可越界  	assert(y0 >= 0 && y0 < map_height); //初始点纵坐标不可越界  	 	assert(map[x0 * map_width + y0]); //初始点应属于可通行点 	 	//上、左、下、右四个方向偏移 	int x_4[] = { 0, -1, 0, 1 }, y_4[] = { -1, 0, 1, 0 };  	int x, y; 	 	typedef std::vector<std::pair<int, int> > route_type; 	typedef std::vector<route_type> 		  route_list; 	 	routes.clear(); 	 	//初始只含有一个长为1的路径 （仅含起始点）  	routes.push_back(route_type(1, std::make_pair(x0, y0)));  	//经过3次遍历扩展，每次扩展根据上一次结果寻找下一步路径  	for (size_t i = 0, k = routes.size(); i < 3; i++) 	{ 		// 遍历上一次寻路结果  		for (size_t m = 0; m < k; m++) 		{ 			// 取最后一个点为起始点  			x = routes[m][i].first, y = routes[m][i].second; 			 			// 4个方向寻找可行的路径  			for (int j = 0; j < 4; j++) 			{ 				x += x_4[j]; 				y += y_4[j]; 				 				// 判定移动到的点有效  				if (x >= 0 && y >= 0 && x < map_width && y < map_height &&  					map[x * map_width + y]) 				{ 					// 判定未曾走过	 					if (std::find(routes[m].begin(), routes[m].end(),  							std::make_pair(x, y)) == routes[m].end()) 					{  						// 依据上次寻路结果加上本次可通行点形成一个新的路径  						route_type route(routes[m]); 						route.push_back(std::make_pair(x, y)); 						 						// 添加到寻路结果中  						routes.push_back(route); 					} 				}				 			} 		} 		 		// 删除上次寻路结果  		routes.erase(routes.begin(), routes.begin() + k); 	}  }

user: user-2
content: 引用 5 楼 BreathOfDeath 的回复:不可以走已经经过的位置，需求说的不是很明白。 。  那就是经典回溯了呀，不用递归的话就用stack模拟递归就好了嘛，对于n比较小的时候（就像你这个n = 4的时候），n重for循环也可以